List或者arraylist去掉重复数据(对象也可以)

本文介绍了一种方法,即使用LinkedHashSet将List或ArrayList中的数据进行加载,并随后将其加载回新的List或ArrayList中,以确保数据的唯一性和顺序性。通过一个具体的测试用例演示了这一过程。

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

方法:将list或者arraylist中的数据加载到linkedhashset中  然后在加载到list或者arraylist中


测试用例如下:

public class TestSet {

	public static void main(String[] args) {
		List<Student> list1 = new ArrayList<Student>();
		list1.add(new Student("张三","12"));
		list1.add(new Student("张三","12"));
		list1.add(new Student("李四","12"));
		list1.add(new Student("王五","15"));
		list1.add(new Student("张三","12"));
		list1.add(new Student("张三","13"));
		System.out.println(list1.toString());
		Set<Student> set = new LinkedHashSet<Student>();
                set.addAll(list1);
                List<Student> list2 = new ArrayList<Student>();
                list2.addAll(set);
                System.out.println(list2.toString());
	}

}


对象:

public class Student {

	String name;
	String age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((age == null) ? 0 : age.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age == null) {
			if (other.age != null)
				return false;
		} else if (!age.equals(other.age))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	public Student(String name, String age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {
		// TODO Auto-generated constructor stub
	}
}



结果

<think>我们有一个ArrayList<Map<String, String>>,需要去除其中复的Map元素。复的定义:两个Map的键值对完全一致(包括键和值都相同,且顺序不影响,因为HashMap的equals方法比较的是内容,与顺序无关)。注意:Map的equals方法已经实现了比较键值对是否相同,所以我们可以直接使用Map的equals方法。但是,由于ArrayList允许复元素,我们需要去除复的Map。思路:1.使用一个新的List(如ArrayList)来存放不复的元素。2.遍历原List,对于每个Map,检查新List中是否已经包含了一个相同的Map(使用contains方法,它会调用Map的equals方法)。3.但是,这样效率较低(O(n^2)),因为每个元素都要遍历新List。另一种思路(效率更高):使用LinkedHashSet(可以保持插入顺序)来去,因为Set不允许复元素。但是,我们存储的是Map对象,而Set判断复是使用equals和hashCode方法,所以我们需要确保Map的equals和hashCode方法能够正确比较(实际上,HashMap已经写了equals和hashCode方法,它比较的是键值对是否相同,所以可以直接使用)。但是注意:我们无法直接将ArrayList<Map>转换为Set,因为Set的泛型是Map,而List的泛型也是Map,所以可以直接用Set<Map<String, String>> set= newLinkedHashSet<>(list);这样set中就没有复了,然后再将set转回ArrayList。但是,这里有一个问题:如果原List中的Map是可变对象,并且我们在去后修改了Map,可能会影响Set中的元素(因为Set中存放的是引用)。不过,在这个场景中,我们只是去,不会修改Map的内容,所以可以接受。步骤:方法1(使用LinkedHashSet保持顺序):Set<Map<String,String>>set =new LinkedHashSet<>(list); //这样就去了,并且保持了原顺序(第一次出现的顺序)ArrayList<Map<String, String>> uniqueList =new ArrayList<>(set);方法2(使用StreamAPI,Java8及以上):List<Map<String,String>>uniqueList= list.stream().distinct().collect(Collectors.toList());但是,distinct()方法内部也是使用equals方法,并且不能保证用哪种Set,所以顺序可能是乱序(实际上,distinct()会保留顺序,因为它是顺序处理的)。但是注意:如果原List中Map的顺序很要,我们想要保留第一次出现的顺序,那么方法1和方法2都可以保留顺序。方法3(使用HashSet,但不保证顺序):如果我们不关心顺序,可以使用HashSet:ArrayList<Map<String,String>>uniqueList= newArrayList<>(new HashSet<>(list));但是这样顺序会丢失。因此,推荐使用LinkedHashSet来保持插入顺序。但是,有一个潜在的问题:两个Map的内容相同,但它们的hashCode计算方式?因为HashMap已经写了hashCode,所以相同内容的Map会有相同的hashCode,所以可以放入Set中去。示例代码:```javaimport java.util.*;public classRemoveDuplicates {publicstatic voidmain(String[] args) {//创建示例数据List<Map<String, String>> list= newArrayList<>();Map<String,String>map1= newHashMap<>();map1.put("name", "张三");map1.put("age", "20");list.add(map1);Map<String,String>map2= newHashMap<>();map2.put("name", "李四");map2.put("age","22");list.add(map2);//添加复的map1Map<String, String> map3 =new HashMap<>();map3.put("name","张三");map3.put("age","20");list.add(map3);System.out.println("去前: "+ list);//使用LinkedHashSet去Set<Map<String,String>>set =new LinkedHashSet<>(list);List<Map<String, String>> uniqueList =new ArrayList<>(set);System.out.println("去后:" +uniqueList);} }```输出:去前:[{name=张三, age=20}, {name=李四, age=22}, {name=张三,age=20}]去后:[{name=张三, age=20}, {name=李四, age=22}]注意:这种方式依赖于Map的equals和hashCode方法。由于HashMap的equals方法比较的是键值对,所以内容相同的Map会被视为相同。但是,如果Map中键值对的顺序不同,例如一个Map是{"name":"张三","age":"20"},另一个是{"age":"20","name":"张三"},那么它们的内容是相同的,但是HashMap的equals方法会认为它们是相等的吗?答案是:是的。因为HashMap的equals方法比较的是键值对的集合,而不考虑顺序。我们可以测试一下:Map<String, String> mapA= newHashMap<>();mapA.put("a", "1");mapA.put("b", "2");Map<String,String>mapB= newHashMap<>();mapB.put("b", "2");mapB.put("a", "1");System.out.println(mapA.equals(mapB));//输出true所以,这种方法可以处理键顺序不同的情况。但是,如果Map中有一个值是null,那么也能正确处理吗?可以,因为HashMap允许null值,并且equals方法会正确处理null。因此,我们推荐使用LinkedHashSet的方法来去,并保持顺序。如果用户使用的Java版本较低(比如低于Java8),那么可以使用循环和Set来手动去(但效率比直接构造LinkedHashSet高,因为不需要先全部放入LinkedHashSet?其实构造方法已经做了,所以一样):Set<Map<String,String>>set =new LinkedHashSet<>();set.addAll(list);List<Map<String,String>>uniqueList= newArrayList<>(set);或者List<Map<String,String>>uniqueList= newArrayList<>();Set<Map<String,String>>seen =new HashSet<>();//这里用HashSet来判断复,但是不保证顺序,所以我们需要用LinkedHashSet来保证顺序?不,我们可以用List的contains方法,但那样效率低。为了保证顺序和效率,我们可以:List<Map<String,String>>uniqueList= newArrayList<>();Set<Map<String,String>>seen =new HashSet<>();//用于快速判断复for (Map<String, String> map: list) {if(seen.add(map)){ //如果此map不在set中,add方法返回trueuniqueList.add(map);}}这样,我们既保证了顺序(第一次出现的顺序),又保证了效率(O(n))。因为HashSet的add和contains操作是O(1)。所以,我们可以选择这种方法,特别是当列表很大时,效率更高。总结:两种方法都可以,根据情况选择。方法1:使用LinkedHashSet直接构造(代码简洁)Set<Map<String,String>>set =new LinkedHashSet<>(list);List<Map<String,String>>uniqueList= newArrayList<>(set);方法2:遍历并利用HashSet检查(效率同样高,且保证顺序)List<Map<String,String>>uniqueList= newArrayList<>();Set<Map<String,String>>seen =new HashSet<>();for (Map<String, String> map: list) {if(!seen.contains(map)) {seen.add(map);uniqueList.add(map);}}//或者使用seen.add(map)的返回值,因为add方法在复时会返回falsefor (Map<String, String> map: list) {if(seen.add(map)) {//如果map不在seen中,则添加并返回trueuniqueList.add(map);}}两种方法都可以,方法1更简洁。但是,方法1的LinkedHashSet在构造时,会遍历整个list并添加到set中,所以也是O(n)。所以效率相当。因此,我们推荐方法1。注意:如果列表非常大,那么方法1和方法2在性能上差异不大,但方法1代码更简洁。但是,方法1在构造LinkedHashSet时,会分配一个初始容量(默认16),当元素很多时,可能会多次扩容。而方法2中,我们可以预先设置HashSet的容量(比如list.size()),避免扩容。所以方法2在性能上可能稍微好一点,但代码稍长。因此,如果对性能要求极高且列表非常大,可以使用方法2并指定初始容量。否则,方法1即可。我们给出两种方法的代码:方法1(简洁):Set<Map<String, String>> set= newLinkedHashSet<>(list);List<Map<String,String>>uniqueList= newArrayList<>(set);方法2(可能避免扩容开销):List<Map<String,String>>uniqueList= newArrayList<>(list.size()); //预分配,但实际大小小于等于list.size()Set<Map<String,String>>seen =new HashSet<>(list.size());//设置初始容量for(Map<String,String>map :list){if (seen.add(map)){uniqueList.add(map);}}一般情况下,方法1足够。最后,我们根据用户需求,给出代码示例。注意:如果Map对象在后续被修改,那么可能会导致问题,因为Set依赖于添加时的hashCode和equals。但是,去后我们返回的是一个新的List,所以通常不会修改原Map。如果用户需要修改,建议使用深拷贝,但这里用户没有要求。因此,我们给出方法1的完整示例。代码示例: ```javaimport java.util.ArrayList; importjava.util.LinkedHashSet;import java.util.List; importjava.util.Map;import java.util.HashMap; importjava.util.Set;public classRemoveDuplicateMaps {publicstatic voidmain(String[] args) {//创建包含复Map的ListList<Map<String, String>> list= newArrayList<>();Map<String,String>map1= newHashMap<>();map1.put("name", "张三");map1.put("age", "20");list.add(map1);Map<String,String>map2= newHashMap<>();map2.put("name", "李四");map2.put("age","22");list.add(map2);//添加一个复的map1Map<String, String> map3 =new HashMap<>();map3.put("name","张三");map3.put("age","20");list.add(map3);//去Set<Map<String, String>> set= newLinkedHashSet<>(list);List<Map<String,String>>uniqueList= newArrayList<>(set);//输出结果System.out.println("原始列表:" +list);System.out.println("去后列表:" +uniqueList);} }```运行结果:原始列表: [{name=张三,age=20},{name=李四,age=22},{name=张三, age=20}]去后列表:[{name=张三, age=20}, {name=李四, age=22}]这样,我们就去除了复的Map元素。注意:如果用户需要根据Map的某个特定键(比如id)来去,而不是整个Map,那么上面的方法就不适用了。因为上面的方法是比较整个Map的内容。但是,用户的问题要求去除复的Map元素,所以我们认为复是指两个Map的所有键值对相同。如果用户需要根据某个键去,那么需要另外的方法,例如使用Stream的toMap方法,指定键,然后如果有复键则保留一个。但这不是用户本次的问题。因此,我们按照用户要求给出答案。</think>### 去除 ArrayList<Map<String, String>> 中的重复数据 在 Java 中,去除 `ArrayList<Map<String, String>>` 中的复 Map 元素,需要基于 Map 的内容进行比较(而非对象引用)。核心方法是利用 `Set` 集合的特性去,同时保持元素顺序。以下是两种推荐方法: --- #### **方法 1:使用 LinkedHashSet(保持顺序)** `LinkedHashSet` 能保留首次出现的元素顺序,同时自动过滤复项: ```java import java.util.*; public class RemoveDuplicates { public static void main(String[] args) { // 原始数据(含复项) List<Map<String, String>> list = new ArrayList<>(); Map<String, String> map1 = new HashMap<>(); map1.put("name", "张三"); map1.put("age", "20"); Map<String, String> map2 = new HashMap<>(); map2.put("name", "李四"); map2.put("age", "22"); Map<String, String> map3 = new HashMap<>(); // 与 map1 内容相同 map3.put("name", "张三"); map3.put("age", "20"); list.add(map1); list.add(map2); list.add(map3); // 去操作 Set<Map<String, String>> set = new LinkedHashSet<>(list); List<Map<String, String>> uniqueList = new ArrayList<>(set); System.out.println("去后结果: " + uniqueList); } } ``` **输出**: ``` 去后结果: [{name=张三, age=20}, {name=李四, age=22}] ``` --- #### **方法 2:使用 Stream API(Java 8+)** 通过 `distinct()` 方法简洁去: ```java import java.util.*; import java.util.stream.Collectors; List<Map<String, String>> uniqueList = list.stream() .distinct() .collect(Collectors.toList()); ``` --- ### **关键说明** 1. **复判定原理** `Map` 的 `equals()` 方法比较**内容**而非对象地址(例如 `{name:"张三"}` 和 `{name:"张三"}` 被视为相同)[^1][^2]。 2. **顺序保留** `LinkedHashSet` 和 `Stream` 默认保留元素首次出现的顺序[^2][^4]。 3. **注意事项** - 若 `Map` 中键的顺序不同(如 `{a:1, b:2}` vs `{b:2, a:1}`),仍视为相同内容(`HashMap` 不保证键顺序)[^1]。 - 如需自定义去逻辑(如按特定段去),需改用 `TreeSet` 或自定义 `Comparator`。 --- ### **应用场景** 此方法适用于: 1. 清洗数据库查询结果中的复记录 2. 合并多个数据源时排除复项 3. 数据导出前的去处理[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值