JAVA中List集合去重的方案,通过Function函数接口自定义一个UniqueSet

本文介绍了一种使用Java 8的Function接口和Set的底层Map特性,自定义一个UniqueSet来根据对象的特定属性进行去重的方法。通过重写add、iterator和size方法,实现了基于对象属性值的唯一性集合。示例代码展示了如何根据Person对象的age属性去重。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Function<T, R>函数接口自定义一个UniqueSet

在开发中,有很多地方需要实现:
一个List中Person对象,根据Person对象中的age年龄去重,留下年龄不重复的集合。

实现方案一:

也是最传统最简单的:emo

        List<Person> list = new ArrayList();
       //将list转成TreeSet 自定义一个比较器compartor

        Set be_set = new TreeSet(new Comparator<Person>() {

            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge().compareTo(o2.getAge());
            }
        });
        be_set.addAll(list);
        return ArrayList(be_set)

这个方案实现原理很简单,将list转换为set;由于set的不可重复的特性,加上自定义比较的comparator,key达到去重的效果。
如果需要的结果不是整个对象,而是普通数据存储[包装类、String]。
则可以更简单的使用JDK8的引入的stream()以及提供的map()接口,collect()接口轻松达到:

     Set<Integer> set =list.stream().map(Person::getAge).collect(Collectors.toSet());
     return new ArrayList(set);

实现方案二:

通过自定义一个唯一规则,定义一个uniqueSet。
通过Function<T,R> 函数式接口,以及Set底层map的特点,实现重复时不添加,不重复添加map的效果。emo
.
Function<T,R>
JDK8引入的函数式接口,其特点是:接受一个T,返回一个R。
其中R的生成规则,可由定义接口时,通过链式 -> XXXX 指定。
比如:

        Function<Integer,Integer> f1  = i->i+2;

则说明,当使用f1.apply(1)时,根据定义的函数i=i+2,会返回一个3出来。
那么通过这样的特性。
我们是不是可以定义一个这样的函数: k = V,
K = “想要去重的属性唯一值
V = “这个唯一值,对应的对象
说做就做,配合Map:

public class UniqueSet<K,V> extends AbstractSet<V> implements Serializable {
    
    private static final long serialVersionUID = 1L;

    //set的底层是一个map,那么我们可以用其中的value,作为判断对象中的唯一属性的媒介
    private Map<K,V> map;
    
    private final Function<V,K> uniqueCondition;

    public UniqueSet(Function<V, K> uniqueCondition) {
        map = new HashMap<>();
        this.uniqueCondition = uniqueCondition;
    }

简单的定义出一个,unique规则的set,但是这也只是个骨架,肉还是来自里面的方法。
那么作为set,在去重中的定位应该是这样的流程:
List转换为set,set在转换为List返回出去。
第一步:
List转换为set,相当于set.addAll(list)
我们调用set.addAll(list)时,由AbstractSet指定。调用其特征类的add方法。
当我们没有重写add方法时,会调用到AbstractSet,然后直接抛出异常。

    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }

重写add(V v):

    @Override
    public boolean add(V v){
        //如果V[对象] 申请出来的值[属性],
        V put = map.put(this.uniqueCondition.apply(v), v);
        return null == put;
    }

this.uniqueCondition.apply(v)申请出来的是对象的属性值。
那么在调用addAll方法时,经过重写的add方法,就会做出如下逻辑:
当这个对象在函数接口中申请出来的值[对象的属性],存在;
由于map的特性,key不可重复,则会覆盖掉之前重复这个属性值的对象。
收集这个新对象。

细节

通过上面定义一个Fuction接口,并且重写add方法。
已经可以达到进入到uniqueSet的集合会由定义的某个属性值去重。
但是我们一定需要重写:iteratorsize

    @Override
    public Iterator<V> iterator() {
        return map.values().iterator();
    }

    @Override
    public int size() {
        return map.size();
    }

理由不言而喻,懂的都懂emo
最后贴出完整的代码和测试。

UniqueSet:

/**
 * @author LeYuna
 * @date 2022-04-17
 *  自定义一个唯一key[对象属性] 的set
 */
public class UniqueSet<K,V> extends AbstractSet<V> implements Serializable {
    
    private static final long serialVersionUID = 1L;

    //set的底层是一个map,那么我们可以用其中的value,作为判断对象中的唯一属性的媒介
    private Map<K,V> map;
    
    private final Function<V,K> uniqueCondition;

    public UniqueSet(Function<V, K> uniqueCondition) {
        map = new HashMap<>();
        this.uniqueCondition = uniqueCondition;
    }
    
    @Override
    public boolean add(V v){
        //如果V[对象] 申请出来的值[属性],
        V put = map.put(this.uniqueCondition.apply(v), v);
        return null == put;
    }
    
    @Override
    public Iterator<V> iterator() {
        return map.values().iterator();
    }

    @Override
    public int size() {
        return map.size();
    }
}

Test测试

    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        Person person = new Person();
        person.setAge(1);
        person.setId("1");
        Person person2 = new Person();
        person2.setAge(1);
        person2.setId("2");
        Person person3 = new Person();
        person3.setAge(3);
        person3.setId("3");
        list.add(person);
        list.add(person2);
        list.add(person3);
        UniqueSet uniqueSet = new UniqueSet<>(Person::getAge);
        uniqueSet.addAll(list);
        ArrayList<Person> arrayList = new ArrayList<>(uniqueSet);
        for(Person person1 : arrayList){
            System.out.println(person1);
        }
    }

结果: Person(id=2, name=null, age=1)
       Person(id=3, name=null, age=3)

版权声明:本站原创文章,于2022-04-17,乐云一发表
转载请注明:leyuna.xyz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值