Java从列表中删除某些属性重复的条目

jmp7cifd  于 2022-12-25  发布在  Java
关注(0)|答案(4)|浏览(126)

我是编程新手,现在面临着一个棘手的问题:我得到了一个包含列表的对象,所以该对象看起来如下所示:

public class SampleClass {
    private UUID id;
    private List<ValueObject> values;
    
    // getters, constructor, etc
}

ValueObject包含一些字符串,如:

public class ValueObject {
    private String firstName;
    private String lastName;
    private String address;

    // getters, constructor, etc
}

我有一个SampleClass示例,其中包含多个ValueObject的列表。一些ValueObject具有相同的firstNamelastName
我想要归档的是,我想要过滤掉一个SampleClass对象中具有相同firstNamelastName的所有ValueObject,并且我想要将最后一个(根据遇到顺序)ValueObject从列表中的每个组副本中保留出来。
我尝试了以下方法:

SampleClass listWithDuplicates = // intializing SampleClass instance

listWithDuplicates.getValues().stream()
    .collect(Collectors.groupingBy(
        ValueObject::getLastname,
        Collectors.toList()
    ));

按姓氏分组,但是我怎么找到匹配的名字,因为姓氏可以相等,但是名字可以不同,所以我想把它保留在我的对象中,因为它不相等。然后怎么删除重复的?谢谢你的帮助

    • 更新**:列表的顺序不应受到删除重复项的影响。

重复项列表
保存SampleClass对象。

ssgvzors

ssgvzors1#

您可以通过使用 * 四参数版本 * 的收集器toMap()来解决此问题,该版本需要以下参数:

  • keyMapper -从流元素生成密钥的函数;
  • *valueMapper -从流元素产生值的函数;
  • mergeFunctino -负责解析Map到相同键的值的函数;
  • mapFunctory -允许指定所需的Map类型。

如果您无法在ValueObject中更改equals/hashCode的实现,则可以引入一个辅助类型作为Key。

public record FirstNameLastName(String firstName, String lastName) {
    public FirstNameLastName(ValueObject value) {
        this(value.getFirstName(), value.getLastName);
    }
}

***注意:*如果您可以在firstNamelastName上覆盖ValueObjectequals/hashCode协定,则不需要上面显示的辅助类型。在下面的代码中,您可以将Function.identity()用作toMap()的keyMapper和valueMapper。

流可以这样实现:

SampleClass listWithDuplicates = // initializing your domain object
    
List<ValueObject> uniqueValues = listWithDuplicates.getValues().stream()
    .collect(Collectors.toMap(
        FirstNameLastName::new, // keyMapper - creating Keys
        Function.identity(),    // valueMapper - generating Values
        (left, right) -> right  // mergeFunction - resolving duplicates
        LinkedHashMap::new      // mapFuctory - LinkedHashMap is needed to preserve the encounter order of the elements
    ))
    .values().stream()
    .toList();
snz8szmq

snz8szmq2#

您可以覆盖ValueObject类中的equalshashCode方法(未测试):

public class ValueObject {

    private String firstName;
    private String lastName;
    private String adress;

    // Constructor...

    // Getters and setters...

    @Override
    public boolean equals(Object obj) {
        return obj == this ||(obj instanceof ValueObject
                    && ((ValueObject) obj).firstName.equals(this.firstName)
                    && ((ValueObject) obj).lastName.equals(this.lastName)
                );
    }

    @Override
    public int hashCode() {
        return (firstName + lastName).hashCode();
    }
    
}

然后,您所需要的就是使用Stream#distinct删除重复项

listWithDuplicates.getValues().stream().distinct()
                .collect(Collectors.groupingBy(ValueObject::getLastname, Collectors.toList()));

您可以阅读this answer以获得更多有关的信息。

xytpbqjk

xytpbqjk3#

我不能把它放到流中,但是如果你真的在valueObject中创建了一个基于name和firstname的equals方法,你可以基于对象进行过滤,把这个放在ValueObject中:

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ValueObject that = (ValueObject) o;
        return Objects.equals(firstName, that.firstName) && Objects.equals(lastName, that.lastName);
    }

那么你应该可以很好地使用这样的循环:

List<ValueObject> listWithoutDuplicates = new ArrayList<>();

for(var vo: listWithDuplicates){
   if(!listWithoutDuplicates.contains(vo)){
        listWithoutDuplicates.add(vo);
         }
 }

但是在流中会更好,..但是如果你实现了equals方法,你可以解决这个问题。

ttygqcqt

ttygqcqt4#

我喜欢已经提供的答案,并认为它们为您给予了答案,但也许出于学习的目的,另一种方法可以是使用Collector,它比较每个ValueObject的firstName和lastName字段,然后只保留最后一个重复的示例。

List<ValueObject> filteredList = listWithDuplicates.getValues().stream()
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(
            vo -> vo.getLastName() + vo.getFirstName(), 
            vo -> vo, 
            (vo1, vo2) -> vo2
        ), 
        map -> new ArrayList<>(map.values())
    ));

因此,您可以使用一个COllector按lastNamefirstName对ValueObject示例进行分组,该COllector创建一个Map,该Map的键是连接在一起的lastNamefirstNamecollectingAndThen收集器将Map转换为ValueObject列表。

相关问题