java 根据多个字段(属性)区分流中收集不同的对象

使用distinctByKeys()函数根据多字段区分

下面的例子中,定义了一个函数,我们可以传递多个键提取器(我们要过滤重复项的字段)。

此函数创建一个键为 List,其中列表包含字段的值以检查不同的条件。

列表键被插入到一个“ConcurrentHashMap”中,它只存储唯一和不同的键。

private static <T> Predicate<T> distinctByKeys(Function<? super T, ?>... keyExtractors) 
{
  final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();

  return t -> 
  {
    final List<?> keys = Arrays.stream(keyExtractors)
                .map(ke -> ke.apply(t))
                .collect(Collectors.toList());

    return seen.putIfAbsent(keys, Boolean.TRUE) == null;
  };
}

示例: 找出不同id和名称的记录:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public class Main 
{
  public static void main(String[] args) 
  {
    List<Record> recordsList = getRecords();
    List<Record> list = recordsList
                .stream()
                .filter(distinctByKeys(Record::getId, Record::getName))
                .collect(Collectors.toList());
    System.out.println(list);
  }
  private static <T> Predicate<T> distinctByKeys(Function<? super T, ?>... keyExtractors) 
  {
    final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();

    return t -> 
    {
      final List<?> keys = Arrays.stream(keyExtractors)
                  .map(ke -> ke.apply(t))
                  .collect(Collectors.toList());

      return seen.putIfAbsent(keys, Boolean.TRUE) == null;
    };
  }
  private static ArrayList<Record> getRecords() 
  {
    ArrayList<Record> records = new ArrayList<>();
    records.add(new Record(1l, 10l, "record1", "record1@email.com", "Netherlands"));
    records.add(new Record(1l, 20l, "record1", "record1@email.com", "Netherlands"));
    records.add(new Record(2l, 30l, "record2", "record2@email.com", "Netherlands"));
    records.add(new Record(2l, 40l, "record2", "record2@email.com", "Netherlands"));
    records.add(new Record(3l, 50l, "record3", "record3@email.com", "Netherlands"));
    return records;
  }
}
https://onitroad.com 更多教程

根据自定义key类的多属性找出唯一元素

另一种可能的方法是使用一个自定义类来表示 POJO 类的不同键。

下面的示例中,创建了一个类 CustomKey,它有一些字段,可以根据所有这些字段的不同值组合从列表中获取 不同的元素(distinct)。

public class CustomKey 
{
  private long id;
  private String name;

  public CustomKey(final Record record) 
  {
    this.id = record.getId();
    this.name = record.getName();
  }

  //Getters and setters

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (id ^ (id >>> 32));
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    CustomKey other = (CustomKey) obj;
    if (id != other.id)
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    return true;
  }
}

示例: 根据给定的多个字段从列表中过滤不同的元素。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public class Main 
{
  public static void main(String[] args) 
  {
    List<Record> recordsList = getRecords();
    List<Record> list = recordsList.stream()
              .filter(distinctByKey(CustomKey::new))
              .collect(Collectors.toList());
    System.out.println(list);
  }
  public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) 
  {
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
  }
  private static ArrayList<Record> getRecords() 
  {
    ArrayList<Record> records = new ArrayList<>();
    records.add(new Record(1l, 10l, "record1", "record1@email.com", "Netherlands"));
    records.add(new Record(1l, 20l, "record1", "record1@email.com", "Netherlands"));
    records.add(new Record(2l, 30l, "record2", "record2@email.com", "Netherlands"));
    records.add(new Record(2l, 40l, "record2", "record2@email.com", "Netherlands"));
    records.add(new Record(3l, 50l, "record3", "record3@email.com", "Netherlands"));
    return records;
  }
}

Record 类:

public class Record 
{
  private long id;
  private long count;
  private String name;
  private String email;
  private String location;

  public Record(long id, long count, String name, 
                  String email, String location) {
    super();
    this.id = id;
    this.count = count;
    this.name = name;
    this.email = email;
    this.location = location;
  }

  //Getters and setters
  @Override
  public String toString() {
    return "Record [id=" + id + ", count=" + count + ", name=" + name + 
                    ", email=" + email + ", location="
                    + location + "]";
  }
}
日期:2020-09-17 00:10:06 来源:oir作者:oir