Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
根据Java 8中的属性从对象列表中删除重复项_Java_List_Java 8 - Fatal编程技术网

根据Java 8中的属性从对象列表中删除重复项

根据Java 8中的属性从对象列表中删除重复项,java,list,java-8,Java,List,Java 8,我正试图根据某些属性从对象列表中删除重复项 我们可以使用Java8以一种简单的方式来实现它吗 List<Employee> employee 列出员工 我们是否可以根据员工的id属性从中删除重复项。我看到过从字符串的arraylist中删除重复字符串的帖子。试试下面的代码: Collection<Employee> nonDuplicatedEmployees = employees.stream() .<Map<Integer, Employee&

我正试图根据某些属性从对象列表中删除重复项

我们可以使用Java8以一种简单的方式来实现它吗

List<Employee> employee
列出员工
我们是否可以根据员工的
id
属性从中删除重复项。我看到过从字符串的arraylist中删除重复字符串的帖子。

试试下面的代码:

Collection<Employee> nonDuplicatedEmployees = employees.stream()
   .<Map<Integer, Employee>> collect(HashMap::new,(m,e)->m.put(e.getId(), e), Map::putAll)
   .values();
Collection nonDuplicatedEmployees=employees.stream()
. collect(HashMap::new,(m,e)->m.put(e.getId(),e),Map::putAll)
.values();

您可以从
列表中获取一个流,并将其放入
树集合中,您可以从中提供一个自定义比较器来唯一地比较id

如果你真的需要一个列表,你可以把这个集合放回ArrayList

import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

...
List<Employee> unique = employee.stream()
                                .collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingInt(Employee::getId))),
                                                           ArrayList::new));

另一个想法是使用包装器包装员工,并根据其id使用equals和hashcode方法:

class WrapperEmployee {
    private Employee e;

    public WrapperEmployee(Employee e) {
        this.e = e;
    }

    public Employee unwrap() {
        return this.e;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        WrapperEmployee that = (WrapperEmployee) o;
        return Objects.equals(e.getId(), that.e.getId());
    }

    @Override
    public int hashCode() {
        return Objects.hash(e.getId());
    }
}
然后包装每个实例,调用
distinct()
,将它们展开并将结果收集到列表中

List<Employee> unique = employee.stream()
                                .map(WrapperEmployee::new)
                                .distinct()
                                .map(WrapperEmployee::unwrap)
                                .collect(Collectors.toList());
List unique=employee.stream()
.map(WrapperEmployee::新建)
.distinct()
.map(包装器员工::展开)
.collect(Collectors.toList());

事实上,我认为您可以通过提供一个函数来进行比较,从而使此包装器具有通用性:

public class Wrapper<T, U> {
    private T t;
    private Function<T, U> equalityFunction;

    public Wrapper(T t, Function<T, U> equalityFunction) {
        this.t = t;
        this.equalityFunction = equalityFunction;
    }

    public T unwrap() {
        return this.t;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        @SuppressWarnings("unchecked")
        Wrapper<T, U> that = (Wrapper<T, U>) o;
        return Objects.equals(equalityFunction.apply(this.t), that.equalityFunction.apply(that.t));
    }

    @Override
    public int hashCode() {
        return Objects.hash(equalityFunction.apply(this.t));
    }
}
公共类包装器{
私人T;
私人职能平等职能;
公共包装器(T,函数equalityFunction){
t=t;
this.equalityFunction=equalityFunction;
}
公共T展开(){
归还这个.t;
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
@抑制警告(“未选中”)
包装器,它=(包装器)o;
返回Objects.equals(equalityFunction.apply(this.t)、that.equalityFunction.apply(that.t));
}
@凌驾
公共int hashCode(){
返回Objects.hash(equalityFunction.apply(this.t));
}
}
映射将是:

.map(e -> new Wrapper<>(e, Employee::getId))
.map(e->new包装器(e,Employee::getId))

直接在列表中执行此操作的最简单方法是

HashSet<Object> seen=new HashSet<>();
employee.removeIf(e->!seen.add(e.getID()));
HashSet seen=newhashset();
employee.removeIf(e->!seen.add(e.getID());
  • removeIf
    将删除满足指定条件的元素
  • Set.add
    如果未修改
    Set
    ,即已包含该值,则将返回
    false
  • 将这两者结合起来,它将删除以前遇到过id的所有元素(员工)

当然,只有当列表支持删除元素时,它才起作用。

另一个简单的版本

BiFunction<TreeSet<Employee>,List<Employee> ,TreeSet<Employee>> appendTree = (y,x) -> (y.addAll(x))? y:y;

TreeSet<Employee> outputList = appendTree.apply(new TreeSet<Employee>(Comparator.comparing(p->p.getId())),personList);
BiFunction appendTree=(y,x)->(y.addAll(x))?y:y;
TreeSet outputList=appendTree.apply(新的TreeSet(Comparator.comparing(p->p.getId()),personList);

如果顺序无关紧要,并且并行运行更有效,则收集到映射,然后获取值:

employee.stream().collect(Collectors.toConcurrentMap(Employee::getId, Function.identity(), (p, q) -> p)).values()

这里有很多很好的答案,但我没有找到关于使用
reduce
方法的答案。因此,对于您的案例,您可以通过以下方式应用它:

List employeeList=employees.stream()
.reduce(新的ArrayList(),(列表累加器,员工)->
{
if(accumulator.stream().noneMatch(emp->emp.getId().equals(employee.getId()))
{
累加器。添加(员工);
}
回流蓄能器;
},(acc1,acc2)->
{
acc1.addAll(acc2);
返回acc1;
});
这对我很有用:

list.stream().distinct().collect(Collectors.toList());

当然,如果可以使用
equals
,则需要实现equals,然后在流中使用
distinct
来过滤列表(请参见上面的答案)。如果您不能或不想覆盖
equals
方法,则可以对任何属性使用
过滤
流,例如属性名称(与属性Id等相同):

Set nameSet=new HashSet();
列出employeesDistinctByName=employees.stream()
.filter(e->nameSet.add(e.getName()))
.collect(Collectors.toList());

另一种解决方案是使用谓词,然后您可以在任何筛选器中使用它:

public static <T> Predicate<T> distinctBy(Function<? super T, ?> f) {
  Set<Object> objects = new ConcurrentHashSet<>();
  return t -> objects.add(f.apply(t));
}
注意:在filter的JavaDoc中,它表示需要一个无状态的predict。实际上,即使流是平行的,这也可以很好地工作


关于其他解决方案:

employees.stream().filter(distinctBy(e -> e.getId));
1) 使用
.collect(Collectors.toConcurrentMap(..).values()
是一个很好的解决方案,但是如果您想排序并保持顺序,这会很烦人


2)
stream.removeIf(e->!seen.add(e.getID())也是另一个非常好的解决方案。但是我们需要确保集合实现了removeIf,例如,如果我们构建集合时使用
数组,它将引发异常。asList(..)

为什么要为该集合使用列表…使用集合而不是列表。是否要搜索employee.name的重复项?或者你的目的是什么,请多给点information@Ranjeet只有当
Employee
正确地实现
equals
hashCode
以正确地识别重复项时,这才有效。很好的答案您的第一个建议比包装的答案要好得多:)。包装是显而易见的,但第一个更好。我没有意识到收集,然后我以这种方式实现了,但有一段时间我在执行测试用例时遇到了空指针异常。奇怪的是,当我重新执行测试用例时,错误消失了。你知道为什么会这样吗。如果您能在这方面帮助我,那就太好了。@Patan如果没有测试用例很难说,请检查列表中是否没有任何空引用。第一个示例对我很有用,但我不明白为什么:)@AvijitBarua您可以根据需要比较任意多的字段。Set<String> nameSet = new HashSet<>(); List<Employee> employeesDistinctByName = employees.stream() .filter(e -> nameSet.add(e.getName())) .collect(Collectors.toList());
public static <T> Predicate<T> distinctBy(Function<? super T, ?> f) {
  Set<Object> objects = new ConcurrentHashSet<>();
  return t -> objects.add(f.apply(t));
}
employees.stream().filter(distinctBy(e -> e.getId));