目录

  • list集合中重复元素的去重
    • 问题由来
    • 方法一:通过两层循环来进行判断(不用重写 hashCode()和equals()方法)
    • 方法二:利用list中contains方法去重(对象重写equals()方法)
    • 方法三:java 8中去重操作(对象需要重写hashCode()和equals()方法)
    • 方法四:HashSet去重操作(对象重写equals()和hashCode()方法)
    • 参考链接

list集合中重复元素的去重

  • 方法一:通过两层循环来进行判断,没有重复的元素就加入到新集合中,新集合中已经有的元素就跳过。
  • 方法二:利用list中contains方法去重——需要重写equals方法
  • 方法三:java 8中去重操作——需要重写HashCode和equals方法
  • 方法四:HashSet去重操作

问题由来

在实际开发的时候,我们经常会碰到这么一个困难:
一个集合容器里面有很多重复的对象,里面的对象没有主键,但是根据业务的需求,实际上我们需要根据条件筛选出没有重复的对象

普通的方式就是利用两层循环来进行判断,没有重复的元素就加入到新集合中,新集合中已经有的元素就跳过。
操作例子如下,创建一个实体对象PenBean,代码如下:

/*
* 笔的实体
* */
@Getter
@Setter
public class PenBean implements Serializable {private static final long serialVersionUID = -4351449138774089396L;//类型private String type;//笔的颜色private String color;public PenBean(String type,String color){this.type = type;this.color = color;}@Overridepublic String toString() {return "PenBean{" +"type='" + type + '\'' +", color='" + color + '\'' +'}';}}

方法一:通过两层循环来进行判断(不用重写 hashCode()和equals()方法)

public static void main(String[] args) {//通过两层循环进行判断 没有重复的元素就加入到新的集合中,新集合中已经有的元素就跳过//添加信息,peabean中没有主键List<PenBean> penBeanList = new ArrayList<>();penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("铅笔","white"));penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("中性笔","white"));penBeanList.add(new PenBean("中性笔","white"));//首先新建一个集合用于存放没有重复的新的数据List<PenBean> newPeanList = new ArrayList<>();//遍历旧的数组for (PenBean penBean : penBeanList) {if(newPeanList.isEmpty()){newPeanList.add(penBean);}else {boolean isSame = false;for (PenBean newPenBean : newPeanList) {//依靠type、color来判断,是否有重复的元素//如果新集合包含元素,直接跳过if(penBean.getType().equals(newPenBean.getType()) && penBean.getColor().equals(newPenBean.getColor())){isSame = true;break;}}if(!isSame){newPeanList.add(penBean);}}}//输出结果System.out.println("=========新数据========");for (PenBean bean : newPeanList) {System.out.println(bean.toString());}}

输出结果

=========新数据======
PenBean{type='铅笔', color='black'}
PenBean{type='铅笔', color='white'}
PenBean{type='中性笔', color='white'}

一般处理数组类型的对象时,可以通过这种方法来对数组元素进行去重操作,以筛选出没有包含重复元素的数组。
那有没有更加简洁的写法呢?
答案肯定是有的,List中的contains()方法就是!


方法二:利用list中contains方法去重(对象重写equals()方法)

在使用contains()之前,必须要对PenBean类重写equals()方法
我们先在PenBean类中重写equals()方法,内容如下:

@Overridepublic boolean equals(Object obj) {if(this == obj){return true;}if(obj == null && getClass() != obj.getClass()){return false;}PenBean penBean = (PenBean) obj;//当type、color 内容都相等的时候,才返回truereturn Objects.equals(type,penBean.getType()) && Objects.equals(color,penBean.getColor());}

修改测试 demo,如下

public static void main(String[] args) {//添加信息List<PenBean> penBeanList = new ArrayList<PenBean>();penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("铅笔","white"));penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("中性笔","white"));penBeanList.add(new PenBean("中性笔","white"));//新数据List<PenBean> newPenBeanList = new ArrayList<PenBean>();//使用contain判断,是否有相同的元素for (PenBean penBean : penBeanList) {if(!newPenBeanList.contains(penBean)){newPenBeanList.add(penBean);}}//输出结果System.out.println("=========新数据======");for (PenBean penBean : newPenBeanList) {System.out.println(penBean.toString());}
}

输出结果如下

=========新数据======
PenBean{type='铅笔', color='black'}
PenBean{type='铅笔', color='white'}
PenBean{type='中性笔', color='white'}

如果PenBean对象不重写equals(),contains()方法的都是false!新数据与源数据是一样的,并不能达到我们想要除去重复元素的目的

那么contains()是怎么做到,判断一个集合里面有相同的元素呢
我们打开ArrayList中contains()方法,源码如下:

public boolean contains(Object o) {return indexOf(o) >= 0;
}

找到indexOf(o)方法,继续往下看,源码如下:

public int indexOf(Object o) {if (o == null) {for (int i = 0; i < size; i++)if (elementData[i]==null)return i;} else {for (int i = 0; i < size; i++)//对象通过 equals 方法,判断是否相同if (o.equals(elementData[i]))return i;}return -1;
}

此时,非常清晰了,如果传入的对象是null,for循环判断数组中的元素是否有null,如果有就返回下标;如果传入的对象不是null,通过对象的equals()方法,for循环判断是否有相同的元素,如果有就返回下标!

如果是数组返回的下标,肯定是大于0,否则返回-1!

这就是为什么在List中使用contains()方法,对象需要重写equals()方法的原因!


方法三:java 8中去重操作(对象需要重写hashCode()和equals()方法)

当然,有些朋友可能会想到 JDK1.8 中的流式写法,例如 jdk1.8 中的集合元素去重写法如下:

public static void main(String[] args) {//添加信息List<PenBean> penBeanList = new ArrayList<PenBean>();penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("铅笔","white"));penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("中性笔","white"));penBeanList.add(new PenBean("中性笔","white"));//使用java8新特性stream进行List去重List<PenBean> newPenBeanList = penBeanList.stream().distinct().collect(Collectors.toList());//输出结果System.out.println("=========新数据======");for (PenBean penBean : newPenBeanList) {System.out.println(penBean.toString());}
}

利用 jdk1.8 中提供的Stream.distinct()列表去重,Stream.distinct()使用hashCode()和equals()方法来获取不同的元素,因此使用这种写法,对象需要重写hashCode()和equals()方法

对PenBean对象重写hashCode()方法,代码如下:

@Override
public int hashCode() {return Objects.hash(type, color);
}

在运行测试demo,结果如下

=========新数据======
PenBean{type='铅笔', color='black'}
PenBean{type='铅笔', color='white'}
PenBean{type='中性笔', color='white'}

即可实现集合元素的去重操作!
那为什么当我们使用String类型的对象作为集合元素时,没有重写呢?

因为 java 中String原生类,已经重写好了,源码如下:

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {@Overridepublic boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}@Overridepublic int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;
}
}

方法四:HashSet去重操作(对象重写equals()和hashCode()方法)

HashSet集合天然支持元素不重复!

实践代码如下!

还是先创建一个对象PenBean,同时重写Object中的equals()和hashCode()方法
如下:

/*** 笔实体*/
public class PenBean {/**类型*/private String type;/**颜色*/private String color;//... 省略 setter 和 getterpublic PenBean(String type, String color) {this.type = type;this.color = color;}@Overridepublic String toString() {return "PenBean{" +"type='" + type + '\'' +", color='" + color + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;PenBean penBean = (PenBean) o;//当type、color 内容都相等的时候,才返回truereturn Objects.equals(type, penBean.type) &&Objects.equals(color, penBean.color);}@Overridepublic int hashCode() {return Objects.hash(type, color);}}

创建测试 demo,如下

public static void main(String[] args) {//添加信息List<PenBean> penBeanList = new ArrayList<PenBean>();penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("铅笔","white"));penBeanList.add(new PenBean("铅笔","black"));penBeanList.add(new PenBean("中性笔","white"));penBeanList.add(new PenBean("中性笔","white"));//新数据List<PenBean> newPenBeanList = new ArrayList<PenBean>();//set去重HashSet<PenBean> set = new HashSet<>(penBeanList);newPenBeanList.addAll(set);//输出结果System.out.println("=========新数据======");for (PenBean penBean : newPenBeanList) {System.out.println(penBean.toString());}
}

输出结果如下

=========新数据======
PenBean{type='铅笔', color='white'}
PenBean{type='铅笔', color='black'}
PenBean{type='中性笔', color='white'}

很明细,返回的新集合没有重复元素!

那HashSet是怎么做的的呢?

打开HashSet的源码,查看我们传入的构造方法如下:

public HashSet(Collection<? extends E> c) {map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));addAll(c);
}

很显然,首先创建了一个HashMap对象,然后调用addAll()方法,继续往下看这个方法!

public boolean addAll(Collection<? extends E> c) {boolean modified = false;for (E e : c)if (add(e))modified = true;return modified;
}

首先遍历List中的元素,然后调用add()方法,这个方法,源码如下:

public boolean add(E e) {return map.put(e, PRESENT)==null;
}

其实,就是向HashMap对象中插入元素,其中PRESENT是一个new Object()常量!

private static final Object PRESENT = new Object();

到这里就基本很清楚了,向HashSet中添加元素,其实等同于

Map<Object,Object> map = new HashMap<Object,Object>();
map.put(e,new Object);//e表示要插入的元素

其中插入的元素e,就是HashMap中的key!

我们知道HashMap,是通过equals()和hashCode()来判断插入的key是否为同一个key,因此,当我们对PenBean对象进行重写equals()和hashCode()时,保证判断是同一个key时,就可以达到元素去重的目的!

最后,对已经去重的集合HashSet,再通过ArrayList中的addAll()方法进行包装,即可得到我们想要的不包含重复元素的数据!

参考链接

https://mp.weixin.qq.com/s/fyncrYIYFFk0fcQTK_S7UQ

(去重)如何去掉list集合中重复的元素相关推荐

  1. 如何去掉list集合中重复元素大全

    如何去掉list集合中重复元素大全 创建实体对象 模拟集合 方法一:遍历实体类的每一个属性 方法二:利用list中contains方法去重 方法三:java 8中流式去重操作 方法四:HashSet去 ...

  2. 【Java面试题】54 去掉一个Vector集合中重复的元素

    在Java中去掉一个 Vector 集合中重复的元素 1)通过Vector.contains()方法判断是否包含该元素,如果没有包含就添加到新的集合当中,适用于数据较小的情况下. import jav ...

  3. 如何将java集合中重复的元素取出来

    今天就给大家讲一下如何将java集合中重复的元素取出来 不多废话,直接代码 此处是对集合中的数字进行查找,其他类型照样适用! List<Integer> list = new ArrayL ...

  4. 数组去重:将一数组中重复的元素去掉剩余部分保存到新数组中

    思路:将旧数组中不重复的元素选取出来放到新数组中,重复的元素只保留一个放到新数组中.首先,需要定义一个新数组用来把保存元素,使用for循环来对旧数组进行遍历.根据旧数组中的元素去查询新数组,利用if条 ...

  5. 获取list集合中重复的元素

    方法1 List<String> words = Arrays.asList("a", "b", "c", "d&qu ...

  6. java快速找出数组或集合中重复的元素

    1.测试方法如下 public class TestArrayRepeat {public static void main(String[] args) {String [] idArr= {&qu ...

  7. android 去重 比较两个list_android 去重 比较两个list_Android 去除list集合中重复项的几种方法...

    因为用到list,要去除重复数据,尝试了几种方法.记录于此... 测试数据: List li1 = new List { "", "", "" ...

  8. android 去重 比较两个list_Android 去除list集合中重复项的几种方法

    因为用到list,要去除重复数据,尝试了几种方法.记录于此... 测试数据: List li1 = new List { "", "", "" ...

  9. 找出集合中重复元素和不重复元素

    //找出集合中重复和不重复元素List<String> list6 = new ArrayList<>();Collections.addAll(list6, "a& ...

最新文章

  1. jmeter tps指标在哪里看_JMeter功能不够用?看这里
  2. All About Monads
  3. linux unbuntu屏幕显示不完整,解决 NetBeans 在 Gnome3 显示不全的问题
  4. Deep Learning(深度学习)学习笔记整理系列之LeNet-5卷积参数个人理解
  5. Eclipse中javascript文件 clg 变为console.log();
  6. html5 - history 历史管理
  7. 为什么我的 Func 如此之慢?
  8. 计算机有新的更新,现在是2018年,我的电脑最近总是弹出说有重要更新,提示自2017年5月9日后,microsoft - Microsoft Community...
  9. 适用于特殊类型自然语言分类的自适应特征谱神经网络
  10. 苹果发布iOS 13.2测试版 iPhone 11拍照更牛了
  11. 设计企业网站大纲_深圳企业网站设计公司|品牌网站设计【尼高网站设计】
  12. *第十三周*数据结构实践项目二【验证Kruskal算法】
  13. Java开发二维码扫一扫名片技术
  14. Mac操作系统-软件安装
  15. 奇谈 2020.11.24日记
  16. java面试常问问题及答案,附源代码
  17. 开源社区的技术债:写代码的“码农”VS 删代码的“清道夫”,谁更该被嘉奖?
  18. 中国民族药产业“十四五”发展重点及投资商机研究报告2021-2027年
  19. java转人工智能_[转]人工智能缩略语大全
  20. 巧用年线抓长线牛股的四种经典技巧

热门文章

  1. e2fsck -y 故障_【计算机论文】非线性编辑系统构建及其故障维护
  2. 深入浅出matplotlib(98):一条曲线多种颜色显示
  3. MicroPython开发ESP32入门笔记 -- 蓝牙篇
  4. Dell Mini 1010
  5. FileZilla Server源码解析之LIST命令
  6. 透明图片怎么发给别人_坦荡书法图片大全下载-抖音坦荡书法图片大全高清 v1.0...
  7. 自定义View分类与流程
  8. 利用Dnspod api批量更新添加DNS解析【python脚本】 - 推酷
  9. php 抓取360搜索数据,360搜索收录 API 接口请求调用
  10. MotionBuilder2018破解版