JAVA中去重复的几个典型的方法

本文介绍了几种Java中去除集合重复元素的方法,从简单的双重循环遍历到利用Set和Map的特性进行高效去重,并提供了代码示例。

不多废话,以说起去重复,大部分人直接想到的就是遍历,比较……从来不考虑程序效率问题,下面把几种常用的比较好理解的去重复的处理方式记录一下,

从简单到难:

1、最简单的,List<String> 这种形式,如果List.size =n 的话,用遍历的方式,循环次数决定了效率。

最垃圾的算法

    public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("1");
		list.add("s");
		list.add("b");
		list.add("1");
		list.add("c");
		for(int i = 0;i<list.size();i++){
			for(int j= 0;j<list.size();j++){
				if(list.get(i).equals(list.get(j))){//发现一箱的,但是i不能等于j,否则就是他自己
					if(i!=j){
						System.out.println("重复"+list.get(i));
					}
				}
			}
		}
		
	}
使用这种方法,循环n*n次,如何处理一下大幅度减少循环的次数呢?
    public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("1");
		list.add("s");
		list.add("b");
		list.add("1");
		list.add("c");
		List<String> list2 = new ArrayList<String>();
		for(int i = 0;i<list.size();i++){
			if(list2.contains(list.get(i))){
				System.out.println("重复"+list.get(i));
			}
			list2.add(list.get(i));
			
		}
		
	}



区别就是多new了一个List,每次判断,如果List里面有,那就是重复的,此时循环次数就剧减,而且list.contains方法的效率要比实际知己遍历list高
然而这两种方法都太Low了,能不能更少循环,更少代码,当然可以。下面我们复习一下list,set,map的区别 都是集合,set不可重复,map键不可重复
根据这个特性,我想直接去重复怎么办?
    public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("1");
		list.add("s");
		list.add("b");
		list.add("1");
		list.add("c");
		Set<String> set = new HashSet<String>();
		set.addAll(list);
		list.clear();
		list.addAll(set);
		
	}



这回你发现了……天啊,不需要写遍历代码了,代码上不用体现循环了。当然用map一样可以做到

好了你说List<String> 太简单了,里面如果是一个复杂对象该咋办,一样可以处理。
假设我们有一个
Point 对象,里面有x,y等属性,但是我们认为,当x和x一样的话,这就是同一个点,怎么办?

首先重写
Point对象的equls方法

public class Point{ //懒得写代码了,暂时用这个代替,这是说明当x,y一样的时候这个点唯一
  private int x; 
  private int y; 
  public Point(int x, int y){ 
    this.x = x; 
    this.y = y; 
  } 

  public boolean equals(Object o){ 
    if(!(o instanceof Point)) 
      return false; 
    Point p = (Point)o; 
      return p.x == x && p.y == y; 
  } 

} 
接下来没错,继续把这个List<Point> 放到set里面……




Java 中校验列表中某几个字段是否存在重复数据有多种方法,以下是一些常见的实现方式: ### 写 `equals` 和 `hashCode` 方法 可以通过写对象的 `equals` 和 `hashCode` 方法,然后使用 `Stream` 的 `distinct` 方法进行,比较原列表和后列表的长度来判断是否有重复数据。以 `Employee` 类的 `name` 和 `age` 两个字段为例: ```java import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; class Employee { private String name; private int age; public Employee(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return age == employee.age && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, age); } public String getName() { return name; } public int getAge() { return age; } } public class Main { public static boolean hasDuplicates(List<Employee> list) { List<Employee> distinctList = list.stream().distinct().collect(Collectors.toList()); return list.size() != distinctList.size(); } public static void main(String[] args) { List<Employee> employees = new ArrayList<>(Arrays.asList( new Employee("Alice", 25), new Employee("Bob", 30), new Employee("Alice", 25) )); boolean result = hasDuplicates(employees); System.out.println("是否存在重复数据: " + result); } } ``` 这种方法通过写 `equals` 和 `hashCode` 方法,让 Java 能够根据 `name` 和 `age` 字段来判断两个 `Employee` 对象是否相等,然后使用流的 `distinct` 方法,最后比较原列表和后列表的长度。如果长度不同,则说明列表中存在重复数据 [^1]。 ### 使用 `Map` 来记录字段组合的出现次数 可以将需要检查重复的字段组合成一个唯一的键,然后使用 `Map` 来记录每个键的出现次数,若有出现次数大于 1 的键,则存在重复数据。 ```java import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; class Employee { private String name; private int age; public Employee(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public class Main { public static boolean hasDuplicates(List<Employee> list) { Map<String, Integer> fieldCountMap = new HashMap<>(); for (Employee employee : list) { String key = employee.getName() + "-" + employee.getAge(); fieldCountMap.put(key, fieldCountMap.getOrDefault(key, 0) + 1); } for (int count : fieldCountMap.values()) { if (count > 1) { return true; } } return false; } public static void main(String[] args) { List<Employee> employees = new ArrayList<>(Arrays.asList( new Employee("Alice", 25), new Employee("Bob", 30), new Employee("Alice", 25) )); boolean result = hasDuplicates(employees); System.out.println("是否存在重复数据: " + result); } } ``` 这段代码将 `name` 和 `age` 组合成一个字符串作为键,使用 `Map` 记录每个键的出现次数,最后遍历 `Map` 的值,如果有大于 1 的值则说明存在重复数据。 ### 使用 `Stream` 和 `Collectors.groupingBy` 方法 可以使用 `Stream` 和 `Collectors.groupingBy` 方法将列表按照指定字段组合进行分组,然后检查分组后的结果中是否有元素数量大于 1 的组。 ```java import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; class Employee { private String name; private int age; public Employee(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public class Main { public static boolean hasDuplicates(List<Employee> list) { Map<String, List<Employee>> groupedEmployees = list.stream() .collect(Collectors.groupingBy(e -> e.getName() + "-" + e.getAge())); return groupedEmployees.values().stream().anyMatch(group -> group.size() > 1); } public static void main(String[] args) { List<Employee> employees = new ArrayList<>(Arrays.asList( new Employee("Alice", 25), new Employee("Bob", 30), new Employee("Alice", 25) )); boolean result = hasDuplicates(employees); System.out.println("是否存在重复数据: " + result); } } ``` 此方法使用 `Collectors.groupingBy` 按照 `name` 和 `age` 组合的字符串对 `Employee` 对象进行分组,然后使用 `anyMatch` 方法检查是否有分组的元素数量大于 1,若有则存在重复数据。 ### 相关问题 1. Java 中使用 `Map` 时,如何处理字段组合的空值情况? 2. 如果列表中的元素是自定义类,且需要根据多个复杂对象字段,该如何实现? 3. 除了 `Stream` 方法,还有哪些高效的 Java 方案? 4. 在高并发场景下,如何安全地对列表中的多个字段进行校验?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值