2022年 11月 16日

Python 字典组成的数组怎么进行去重?

你知道吗?如果数组是字典组成的,直接对数组内的字典采用set的方式进行去重,会报错:

  1. test = [{"a": 1}, {"a": 1}, {"a": 3}, {"b": 4}]
  2. test = list(set(test))
  3. >>>TypeError: unhashable type'dict'

 

因为使用set去重的前提是该对象为不可变对象,而字典是可变对象,因此无法直接使用该方法去重。

那么怎么解决这个问题呢?有三个办法。

Image

1.使用reduce方法

reduce() 函数会对参数序列中元素进行累积。

比如:

  1. from functools import reduce
  2. >>>def add(x, y) :            # 两数相加
  3. ...    return x + y
  4. ...
  5. >>>reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
  6. 15

 

上述写法也能用lambda函数简化为:

  1. from functools import reduce
  2. >>> reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
  3. 15

 

因此,我们自己编写一个函数进行数组内的字典去重:

  1. from functools import reduce
  2. data = [{"a"1}, {"a"1}, {"a"3}, {"b"4}]
  3. result = []
  4. def unduplicate(result, data):
  5.     if data not in result:
  6.         result = result + [data]
  7.     return result
  8. for i in data:
  9.     result = unduplicate(result, i)
  10. >>> result
  11. >>> [{'a'1}, {'a'3}, {'b'4}]

 

稍显复杂,如果使用reduce函数和lambda函数,代码能简化很多:

  1. def delete_duplicate(data):
  2.     func = lambda x, y: x + [y] if y not in x else x
  3.     data = reduce(func, [[], ] + data)
  4.     return data
  5. >>> delete_duplicate(data)
  6. >>> [{'a'1}, {'a'3}, {'b'4}]

 

当然, 我也能一行写完这个功能:

data = reduce(lambda x, y: x + [yif y not in x else x, [[], ] + data)

 

只不过有可能会被打死在工位上,所以不建议这么干。

Image

2.奇怪的技巧

就如文章开头提到的,字典之所以不能用set去重,是因为它是可变对象。

但是…如果我们把它变成不可变对象呢?

  1. data = [{"a"1}, {"a"1}, {"a"3}, {"b"4}]
  2. def delete_duplicate(data):
  3.     immutable_dict = set([str(item) for item in data])
  4.     data = [eval(i) for i in immutable_dict]
  5.     return data
  6. >>> delete_duplicate(data)
  7. >>> [{'a'1}, {'a'3}, {'b'4}]

 

没错,这能成。

Image

1.遍历字典,将每个子项变成字符串存放到数组中,再通过set函数去重。

2.通过eval函数,将去重后的数组里的每个子项重新转化回字典。

如此Python,怎能不好玩?

 

3.高效的方式

上面讲了两种骚操作,其实都不太建议在实际工作中使用。

一个原因是真的太骚了,怕被打趴在工位上。

另一个原因是,它们在应对较大数据量的时候,性能不太行。

下面是最正统的方式:

  1. data = [dict(t) for t in set([tuple(d.items()) for d in data])]
  2. >>>data
  3. >>>[{'a': 1}, {'b': 2}]

在这里还是要推荐下我自己建的Python开发学习QQ群:705933274(即可获取使用到的代码文件及数据),群里都是学Python开发的,如果你想学或者正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2021最新的Python进阶资料和高级开发教程,欢迎进阶中和进想深入Python的小伙伴!

其实和第二种方式一样,是将数组内的每个字典转成元组,也就是不可变对象,再使用set进行去重。去重完毕后再使用dict函数将元组重新组成字典对。

但是,这种方法对于字典内还有字典的数据结构是不适用的,因此对于字典对里还有字典情况的去重,比如:

data2 = [{"a": {"b""c"}}, {"a": {"b""c"}}]

 

这种情况我建议使用第二种方式去重:

  1. data2 = [{"a": {"b""c"}}, {"a": {"b""c"}}]
  2. def delete_duplicate_str(data):
  3.     immutable_dict = set([str(item) for item in data])
  4.     data = [eval(i) for i in immutable_dict]
  5.     return data
  6. print(delete_duplicate_str(data2))
  7. >>> [{'a': {'b''c'}}]

 

怎么样,这三种方式你都学会了吗?

如果觉得有收获的话记得收藏一下。以后遇到类似的去重场景时可以拿出阅读一下。