集合去重复那些事(三)

编程

接上一篇: https://my.oschina.net/dtz/blog/4482631

留的一个问题解答如下

反例:本方法是串行条件过滤,不是两个参数同时成立

  userList.stream().filter(

                DistinctUtils.distinctBykey(User::getName)

                        .and(DistinctUtils.distinctBykey(User::getAddr)))

                .forEach(p->{

                    System.err.println(p.getName()+","+p.getAddr());

                });

方法一:有点笨,但是也管用

for (int i = 0; i < userList.size(); i++) {

for (int j = 0;j<userList.size(); j++) {

if (i!=j && userList.get(j).getName().equals(userList.get(i).getName())

&&userList.get(j).getAddr().equals(userList.get(i).getAddr())) {

//删除重复元素

userList.remove(userList.get(j));

}

}

}

方法二:stream+filter+map,解决方案就是多个参数拼接成一个参数

userList.stream()

.filter(p->DistinctUtils.distinctBykey(p.getName()+p.getAddr()).test(p))

.collect(Collectors.toList());

 方法三:stream+filter+map,解决方案就是多个参数拼接成一个参数

userList.stream()

.filter(DistinctUtils.distinctBykey(user->user.getName()+user.getAddr()))

.collect(Collectors.toList());

方法四:stream+TreeSet,解决方案就是多个参数拼接成一个参数

userList.stream().collect(Collectors.collectingAndThen(

Collectors.toCollection(() -> new TreeSet<>(

Comparator.comparing(user -> user.getAddr() + ";" + user.getName()))), ArrayList::new));

 

 

 

附录信息:提供工具方法和实体类JDK源码如下:

/**

* @author dingzhen

*/

public class DistinctUtils {

public static <T> Predicate<T> distinctBykey(Function<? super T,?> keyFunction){

Map<Object, Boolean> objectMap = new ConcurrentHashMap<>();

return t -> objectMap.putIfAbsent(keyFunction.apply(t), Boolean.TRUE) == null;

}

public static <T> Predicate<T> distinctBykey(String keyFunction){

Map<Object, Boolean> objectMap = new ConcurrentHashMap<>();

return t -> objectMap.putIfAbsent(keyFunction, Boolean.TRUE) == null;

}

}

 

 

首先是filter方法,返回一个流,需要一个Predicate类型的参数(Predicate这个函数式接口,接受一个参数,返回布尔值)

Stream<T> filter(Predicate<? super T> predicate)

filter根据Predicate返回的布尔值来判断是否要过滤掉,会过滤掉返回值为false的数据。自己定义的distinctByKey返回值就是Predicate

所以可以作为参数传入filterdistinctByKey也需要一个Function的参数。

distinctByKey先是定义了一个线程安全的Map(相比于Hashtable以及Collections.synchronizedMap()

ConcurrentHashMap在线程安全的基础上提供了更好的写并发能力,但同时降低了对读一致性的要求)

因为在流计算中是多线程处理的,需要线程安全。然后将值作为key,TRUE作为value putmap中。

这里的put方法使用的是putIfAbsent()putIfAbsent()方法是如果key不存在则putmap中,并返回null

key存在,则直接返回key所对应的value值。

所以 seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;

这里用 == null判断是否存在于map了,若存在则返回false,不存在则为true以用来达到去重的目的。

default V putIfAbsent(K key, V value) {

V v = get(key);

if (v == null) {

v = put(key, value);

}

return v;

}

注:putIfAbsent()定义在Map接口中,是默认方法。

源码:

/**

* Represents a predicate (boolean-valued function) of one argument.

*

* <p>This is a <a href="package-summary.html">functional interface</a>

* whose functional method is {@link #test(Object)}.

*

* @param <T> the type of the input to the predicate

*

* @since 1.8

*/

@FunctionalInterface

public interface Predicate<T> {

/**

* Evaluates this predicate on the given argument.

*

* @param t the input argument

* @return {@code true} if the input argument matches the predicate,

* otherwise {@code false}

*/

boolean test(T t);

/**

* Represents a function that accepts one argument and produces a result.

*

* <p>This is a <a href="package-summary.html">functional interface</a>

* whose functional method is {@link #apply(Object)}.

*

* @param <T> the type of the input to the function

* @param <R> the type of the result of the function

*

* @since 1.8

*/

@FunctionalInterface

public interface Function<T, R> {

/**

* Applies this function to the given argument.

*

* @param t the function argument

* @return the function result

*/

R apply(T t);

/**

* If the specified key is not already associated with a value (or is mapped

* to {@code null}) associates it with the given value and returns

* {@code null}, else returns the current value.

*

* @implSpec

* The default implementation is equivalent to, for this {@code

* map}:

*

* <pre> {@code

* V v = map.get(key);

* if (v == null)

* v = map.put(key, value);

*

* return v;

* }</pre>

*

* <p>The default implementation makes no guarantees about synchronization

* or atomicity properties of this method. Any implementation providing

* atomicity guarantees must override this method and document its

* concurrency properties.

*

* @param key key with which the specified value is to be associated

* @param value value to be associated with the specified key

* @return the previous value associated with the specified key, or

* {@code null} if there was no mapping for the key.

* (A {@code null} return can also indicate that the map

* previously associated {@code null} with the key,

* if the implementation supports null values.)

* @throws UnsupportedOperationException if the {@code put} operation

* is not supported by this map

* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)

* @throws ClassCastException if the key or value is of an inappropriate

* type for this map

* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)

* @throws NullPointerException if the specified key or value is null,

* and this map does not permit null keys or values

* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)

* @throws IllegalArgumentException if some property of the specified key

* or value prevents it from being stored in this map

* (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)

* @since 1.8

*/

default V putIfAbsent(K key, V value) {

V v = get(key);

if (v == null) {

v = put(key, value);

}

return v;

}

package com.dingzhen;

/**

* @author dingzhen

*/

public class User {

private String name;

private Integer age;

private String addr;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

public String getAddr() {

return addr;

}

public void setAddr(String addr) {

this.addr = addr;

}

}

以上是 集合去重复那些事(三) 的全部内容, 来源链接: utcz.com/z/519276.html

回到顶部