List去重的几种方法

本文介绍了Java中去除List重复元素的多种方法,包括使用HashSet、TreeSet、LinkedHashSet、Collections.frequency以及Stream API的distinct方法。详细展示了每种方法的实现代码及效果,例如HashSet去重不保持原有顺序,而LinkedHashSet则能保持顺序。

//HashSet是通过Hashcode和equals去重
//Treeset默认是通过自然排序接口去重

//colections.sort() 或者List.sort()不能去重,因为使用的是排序算法(比如jdk6的归并排序,jdk7的二叉排序)

@Test
public void test1() {

List lists = Arrays.asList(“aa”, “a”, “AA”, “aa”, “bb”, “cc”,
“ss”, “ss”);
List lists2 = new ArrayList();
// 方式1:遍历每个元素,使用新集合添加的时候进行重复判断 保持了原来的顺序
for (String s1 : lists) {
if (!lists2.contains(s1)) {
lists2.add(s1);
}
}
//为了避免内存浪费
lists=null;
System.out.println(lists2);

}

@Test
public void test2() {
//保留了原来的排序
List lists = Arrays.asList(“aa”,“a”,“AA”,“aa”,“bb”,“cc”,“ss”,“ss”,“ss”,“aa”,“aa”);
//因为:Arrays.asList()返回一个受指定数组支持的固定大小的列表。所以不能做Add、Remove等操作。
lists=new ArrayList(lists);
for (int i = 0; i < lists.size()-1; i++) {
for (int j =lists.size()-1 ; j >i; j–) {
if (lists.get(i).equals(lists.get(j))) {
lists.remove(j);
}
}
}
// 或者
// for (int i = 0; i < lists.size()-1; i++) {
// for (int j = i+1; j < lists.size(); j++) {
// if (lists.get(i).equals(lists.get(j))) {
// //注意在删除时有一个顶替的过程
// lists.remove(j);
// j–;
// }
// }
// }
System.out.println(lists);
}

@Test
public void test3() {
List lists = Arrays.asList(“aa”,“a”,“AA”,“aa”,“bb”,“cc”,“ss”,“ss”);

//使用TreeSet的排序去重,结果是排序之后的
// lists=new ArrayList(new TreeSet(lists));
// System.out.println(“去重1:”+lists);

//使用HashSet的排序去重,结果是排序是随机的
// lists=new ArrayList(new HashSet(lists));
// System.out.println(“去重2:”+lists);

// 使用LinkedHashSet的排序去重,结果是原来的排序 (推荐)
lists=new ArrayList(new LinkedHashSet(lists));
System.out.println(“去重3:”+lists);

}

// 使用Collections.frequency ,看底层源码,他会统计每个元素的个数,所以性能不好
@Test
public void test4() {
//不能保持原来的排序,会删除第一个出现的重复值
// Collections.frequency(Collection Object o):返回指定集合中指定对象出现的次数
List lists = Arrays.asList(“d”,“aa”,“a”,“AA”,“aa”,“bb”,“aa”,“cc”,“ss”,“ss”,“ss”);
lists=new ArrayList(lists);

for (int i = 0; i < lists.size(); i++) {
//如果一个元素出现2次以上,删除这个元素
if ( Collections.frequency(lists, lists.get(i))>1) {
lists.remove(i);
}
}
System.out.println(lists);
}

//Stream java8
@Test
public void test5() {
List lists = Arrays.asList(“d”,“aa”,“a”,“AA”,“aa”,“bb”,“aa”,“cc”,“ss”,“ss”,“ss”);
//distinct根据hashcode和equals来去重
lists = lists.stream().distinct().collect(Collectors.toList());
System.out.println(lists);
}

<think>我们正在讨论列表方法。根据之前的引用和常见方法,我们可以总结几种不同的列表方法,并分析它们的优缺点和适用场景。 常见方法包括: 1. 使用集合(set):将列表转换为集合,因为集合不允许复元素,所以可以快速,然后再转回列表。但这种方法会丢失原始列表的顺序。 2. 使用字典(dict):利用字典键的唯一性,我们可以将列表元素作为字典的键,这样也可以,并且可以保留顺序(在Python3.7及以上版本中,字典保留插入顺序)。 3. 使用列表推导式或循环:遍历列表,将不复的元素添加到新列表中。这种方法可以保留顺序。 4. 使用collections.Counter:类似于字典,也可以用来,但主要用于计数,后同样可以保留顺序(按元素首次出现的顺序)。 另外,引用[1]提到了使用集合的时间复杂度是O(n),但需要额外内存,且元素必须可哈希。引用[2]和[4]提到了计数的方法,但不一定需要计数,所以我们可以选择是否计数。 下面我们将具体列出几种方法,并给出代码示例,同时说明每种方法的特点(是否保序、时间复杂度、空间复杂度)。 注意:用户的问题中要求的是方法,以及它们的数量(即有多少种方法)。但我们通常不会固定说只有几种,而是列举常用方法。我们这里列举4种主要方法。 具体方法如下: 方法1:使用集合(set)(不保序) 方法2:使用字典(dict)并保留顺序(保序) 方法3:使用循环遍历并保留顺序(保序) 方法4:使用collections.OrderedDict(在旧版本Python中保序)或者直接使用dict(在Python3.6以上版本中保序) 实际上,方法2和方法4在较新的Python版本中都可以用dict实现保序。 我们还可以提到使用列表推导式配合not in判断,但这种方法效率较低(O(n^2)),适用于小列表。 下面我们用代码示例展示: 注意:我们不需要计数,只是。 代码示例: </think>以下是Python中列表的常用方法总结,共7种主要方法及其技术特点: ### 1. 集合转换法(最快方法) 利用集合数据结构自动的特性实现: ```python original_list = [10, 20, 30, 40, 50, 20, 30, 20] unique_list = list(set(original_list)) print(unique_list) # 输出:[40, 10, 50, 20, 30] ``` - **时间复杂度**:$O(n)$ - **空间复杂度**:$O(n)$ - **特点**:高效但**不保留原始顺序**[^1] ### 2. 字典键值法(保序) 利用字典键的唯一性保持原始顺序: ```python unique_list = list(dict.fromkeys(original_list)) print(unique_list) # 输出:[10, 20, 30, 40, 50] ``` - **时间复杂度**:$O(n)$ - **最佳实践**:Python 3.6+ 版本可完美保持顺序 ### 3. 列表遍历法(基础) 通过循环手动过滤复元素: ```python unique_list = [] for item in original_list: if item not in unique_list: unique_list.append(item) print(unique_list) # 输出:[10, 20, 30, 40, 50] ``` - **时间复杂度**:$O(n^2)$ - **适用场景**:小数据集或需自定义逻辑时 ### 4. 列表推导式法(简洁) 单行实现顺序保序的: ```python unique_list = [] [unique_list.append(x) for x in original_list if x not in unique_list] print(unique_list) # 输出:[10, 20, 30, 40, 50] ``` ### 5. collections.Counter法(带计数) 获取列表的同时统计元素频次: ```python from collections import Counter counter = Counter(original_list) unique_list = list(counter.keys()) print(unique_list) # 输出:[10, 20, 30, 40, 50] print(counter[20]) # 输出:3(元素20出现次数)[^4] ``` ### 6. 有序字典法(旧版本兼容) 兼容Python 3.6以下版本的保序方案: ```python from collections import OrderedDict unique_list = list(OrderedDict.fromkeys(original_list)) ``` ### 7. 迭代工具法(复杂场景) 使用itertools处理高级需求: ```python import itertools # 按连续 unique_list = [k for k,g in itertools.groupby(sorted(original_list))] ``` ### 方法对比表 | 方法 | 是否保序 | 时间复杂度 | 额外功能 | 适用场景 | |--------------------|----------|------------|--------------|--------------------| | 集合转换法 | ❌ | $O(n)$ | 无 | 大数据集快速 | | 字典键值法 | ✅ | $O(n)$ | 无 | 常规保序需求 | | 列表遍历法 | ✅ | $O(n^2)$ | 可定制逻辑 | 小数据集 | | collections.Counter| ✅ | $O(n)$ | 元素计数 | 需统计频次场景[^4] | | 有序字典法 | ✅ | $O(n)$ | 无 | Python <3.6版本 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值