java multiple_Java 8 stream distinct by multiple fields

通过比较 Java 8 多个字段或属性,学习collect distinct objects from a stream中collect distinct objects from a stream 。

1. Distinct by multiple fields – distinctByKeys() function

下面给出的是一个接受varargs参数的函数,我们可以传递多个键提取器(我们要在其上过滤重复项的字段)。

此函数将键创建为List ,其中list包含用于检查不同组合的字段的值。 列表键插入到ConcurrentHashMap ,该键仅存储唯一且不同的键。private static Predicate distinctByKeys(Function super T, ?>... keyExtractors)

{

final Map, 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;

};

}

在给定的示例中,我们发现所有具有distinct ids and name记录。 我们应该只有3条记录作为输出。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 recordsList = getRecords();

List list = recordsList

.stream()

.filter(distinctByKeys(Record::getId, Record::getName))

.collect(Collectors.toList());

System.out.println(list);

}

private static Predicate distinctByKeys(Function super T, ?>... keyExtractors)

{

final Map, 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 getRecords()

{

ArrayList records = new ArrayList<>();

records.add(new Record(1l, 10l, "record1", "record1@email.com", "India"));

records.add(new Record(1l, 20l, "record1", "record1@email.com", "India"));

records.add(new Record(2l, 30l, "record2", "record2@email.com", "India"));

records.add(new Record(2l, 40l, "record2", "record2@email.com", "India"));

records.add(new Record(3l, 50l, "record3", "record3@email.com", "India"));

return records;

}

}

Program output.[

Record [id=1, count=10, name=record1, email=record1@email.com, location=India],

Record [id=2, count=30, name=record2, email=record2@email.com, location=India],

Record [id=3, count=50, name=record3, email=record3@email.com, location=India]

]

2. Distinct by multiple properties – Custom key class

另一种可能的方法是使用一个自定义类,该类代表POJO类的不同键。 在我们的案例中,我们创建了一个CustomKey类,该类可以具有任意多个字段,并且列表中的不同元素将基于所有这些字段的值的不同组合来获取。

在给定的示例中,我们再次发现所有具有唯一键和名称的记录。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 recordsList = getRecords();

List list = recordsList.stream()

.filter(distinctByKey(CustomKey::new))

.collect(Collectors.toList());

System.out.println(list);

}

public static Predicate distinctByKey(Function super T, Object> keyExtractor)

{

Map seen = new ConcurrentHashMap<>();

return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;

}

private static ArrayList getRecords()

{

ArrayList records = new ArrayList<>();

records.add(new Record(1l, 10l, "record1", "record1@email.com", "India"));

records.add(new Record(1l, 20l, "record1", "record1@email.com", "India"));

records.add(new Record(2l, 30l, "record2", "record2@email.com", "India"));

records.add(new Record(2l, 40l, "record2", "record2@email.com", "India"));

records.add(new Record(3l, 50l, "record3", "record3@email.com", "India"));

return records;

}

}

Program output.[

Record [id=1, count=10, name=record1, email=record1@email.com, location=India],

Record [id=3, count=30, name=record2, email=record2@email.com, location=India],

Record [id=5, count=50, name=record3, email=record3@email.com, location=India]

]

作为参考,我们使用了下面给出的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 + "]";

}

}

Read More:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值