List对象集合里面针对某一个属性去重

     前一段时间写一些统计类的功能,需要对一个类里面几个联合的属性做唯一性的筛选,我就搜了一下关于java8关于Lambda表达式,不得不说,Lambda还是和强大的。废话不说了,下面就直接贴代码啦!

   ArrayList<User> collect = dataList.stream().collect( collectingAndThen( toCollection(() -> new TreeSet<>(Comparator.comparing(User::getKey))), ArrayList::new) );

注:我把需要做唯一性筛选的几个属性组合成了一个属性--key,dataList是需要做筛选的数据集合。

 

<think>我们有一个需求:在Android开发中,对存储实体类对象List集合进行,并且可能需要根据实体类的某个属性进行,同时合并某些字段(如相加)。根据提供的引用,我总结了以下几种方法:方法1:使用HashMap(引用[1])思路:遍历原始List,利用HashMap的key唯一性。如果遇到复的key(根据实体类的equals和hashCode判断),则合并两个对象(例如,将某个字段相加)。最后,将HashMap的values取出作为后的List。方法2:写实体类的equals和hashCode方法(引用[2][3])思路:在实体类中写equals和hashCode方法,使得当两个对象的特定属性(如id或姓名和年龄组合)相同时,就认为它们相等。然后我们可以利用HashSet进行(因为HashSet不允许复元素)。注意:这种方法只适用于整个对象,不能直接合并字段。方法3:使用TreeSet(引用[4])思路:使用TreeSet并传入一个自定义的Comparator,在Comparator中指定根据哪个属性。同时,在Comparator中也可以处理相同属性时的合并逻辑(但注意,TreeSet的Comparator主要用于排序和,合并逻辑通常需要额外处理,上述引用中的代码仅实现了,没有合并字段)。如果要在时合并字段,我们需要在Comparator判断相等时,修改原有的对象(但这样会破坏Set的约定,因为Set要求不变性),所以更好的方式还是使用方法1。因此,针对需求:1.如果的同时需要合并某些字段(比如数量相加),使用方法1(HashMap)是更合适的。2.如果只是根据某些属性(不需要合并),使用方法2(写equals和hashCode,然后用HashSet)或方法3(TreeSet)都可以。下面分别给出两种情况的代码示例:情况1:并合并字段(例如,根据零件编号,并合并数量)假设Parts实体类如下:```publicclassParts{privateStringpartNo;//零件编号,用于判断是否复privateintquantity;//需要合并的字段//构造方法、getter、setter省略//合并两个对象:将数量相加publicstaticPartsmerge(PartsoldPart,PartsnewPart){//假设我们根据partNo已经确定这两个对象是同一个零件oldPart.setQuantity(oldPart.getQuantity()+newPart.getQuantity());returnoldPart;}//写equals和hashCode,使得partNo相同的Parts对象被认为是相等的@Overridepublicbooleanequals(Objecto){if(this==o)returntrue;if(o==null||getClass()!=o.getClass())returnfalse;Partsparts=(Parts)o;returnpartNo.equals(parts.partNo);}@OverridepublicinthashCode(){returnObjects.hash(partNo);}}```使用HashMap并合并:```List<Parts>partsList=newArrayList<>();//假设partsList已经添加了一些Parts对象Map<Parts,Parts>map=newHashMap<>();for(Partspart:partsList){//如果map中已经存在这个零件(根据partNo判断),则合并if(map.containsKey(part)){PartsexistPart=map.get(part);//合并数量(也可以使用上面的merge方法)existPart.setQuantity(existPart.getQuantity()+part.getQuantity());}else{//这里我们直接放入当前的part对象,注意:我们也可以选择clone一个新的对象放入,以免影响原对象map.put(part,part);}}//将合并后的结果转为ListList<Parts>distinctList=newArrayList<>(map.values());```情况2:仅(不合并字段)如果只需要根据某些属性,不需要合并字段,那么使用HashSet更简单。示例1:写实体类的equals和hashCode方法如上面的Parts实体类已经写了equals和hashCode(根据partNo),那么:```List<Parts>partsList=...;//使用HashSetSet<Parts>set=newHashSet<>(partsList);List<Parts>distinctList=newArrayList<>(set);```示例2:使用TreeSet自定义比较器如果我们不想修改实体类的equals和hashCode(或者根据临时条件),可以使用TreeSet:```List<Parts>partsList=...;//创建TreeSet,并指定比较器(根据零件编号)Set<Parts>set=newTreeSet<>(newComparator<Parts>(){@Overridepublicintcompare(Partso1,Partso2){returno1.getPartNo().compareTo(o2.getPartNo());}});set.addAll(partsList);List<Parts>distinctList=newArrayList<>(set);```注意:TreeSet的比较器中,如果compare返回0,则认为是相同的对象,所以只会保留一个。因此,我们可以根据需求在比较器中定义哪些属性相同即为复。总结:1.并合并字段:使用HashMap,在遇到复时进行字段合并操作。2.仅:使用HashSet(需写equals和hashCode)或TreeSet(自定义Comparator)。根据实际需求选择合适的方法。相关问题:1.在HashMap并合并字段的方法中,如果不修改原有的对象,应该如何处理?2.使用TreeSet时,如果比较器返回0,为什么Set会认为两个对象相同?3.如果属性是多个字段(比如姓名和年龄),应该怎样写equals和hashCode方法?</think> 在Android开发中,使用List存储实体类并进行,主要有以下几种方法: ### 方法1:通过写实体类`equals()`和`hashCode()` ```java // 实体类示例 public class Person { private String name; private int age; // 写equals()和hashCode() @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } } // 操作 List<Person> distinctList = new ArrayList<>(new HashSet<>(originalList)); ``` **原理**: 当实体类写`equals()`和`hashCode()`后,`HashSet`会根据这两个方法判断对象是否复[^2][^3]。 --- ### 方法2:使用`TreeSet`自定义规则 ```java Set<Person> set = new TreeSet<>(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { // 按name和age组合 int nameCompare = o1.getName().compareTo(o2.getName()); if (nameCompare != 0) return nameCompare; return Integer.compare(o1.getAge(), o2.getAge()); } }); set.addAll(originalList); List<Person> distinctList = new ArrayList<>(set); ``` **注意**:`TreeSet`的比较器必须保证: - 返回0时表示对象复 - 返回非0时确定排序顺序[^4] --- ### 方法3:使用Stream API(Java 8+) ```java List<Person> distinctList = originalList.stream() .collect(Collectors.collectingAndThen( Collectors.toCollection( () -> new TreeSet<>(Comparator.comparing(Person::getName)) ), ArrayList::new )); ``` **优势**:代码简洁,支持链式操作 --- ### 方法4:使用LinkedHashSet保持顺序 ```java Set<Person> set = new LinkedHashSet<>(originalList); List<Person> distinctList = new ArrayList<>(set); ``` **特点**:在的同时保留原始顺序 --- ### 特定需求:并合并字段 参考引用[1]的HashMap合并方案: ```java Map<Person, Person> map = new HashMap<>(); for (Person p : originalList) { if (map.containsKey(p)) { // 合并操作(例如数量相加) Person exist = map.get(p); exist.setCount(exist.getCount() + p.getCount()); } else { map.put(p, p); } } List<Person> mergedList = new ArrayList<>(map.values()); ``` --- **选择建议**: 1. 只需简单 → `HashSet`+写`equals()/hashCode()` 2. 需自定义规则 → `TreeSet`+比较器 3. 需保留顺序 → `LinkedHashSet` 4. 需合并字段 → `HashMap`遍历合并 ### 相关问题 1. 如何在`equals()`方法中处理多个字段的组合? 2. 使用`TreeSet`时如何避免影响排序顺序? 3. 如何实现Android中的实体类数据变化自动更新UI? 4. 在合并字段时如何避免修改原始数据对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值