【发布时间】:2016-08-19 07:38:22
【问题描述】:
我有包含许多重复项的庞大对象列表(我说的是数千个列表,每个列表包含数千个对象,最多包含大约 1000 万个单独的对象(已经没有重复项)。
我需要遍历它们并删除每个列表中的所有重复项(无需在列表之间进行比较,只在每个列表中进行比较)。
当然,我可以浏览这些列表并与已多次发布的任何重复数据删除算法进行比较,但我想这将花费我很长时间。
我认为我可以使用精心设计的 __hash__ 方法创建一个对象并使用 list(set(obj)) 删除它们,但首先:我不知道这是否可行,其次:我仍然需要循环列表以将元素转换为新对象。
我知道 Python 不是我想要实现的最佳解决方案,但在这种情况下,它必须在 Python 中完成。我想知道以最佳性能实现这一目标的最佳方法是什么。
编辑:澄清一下:我有大约 2k 个对象列表,每个对象中大约有 5k 个对象(粗略估计)。复制的对象是副本,而不是对同一内存位置的引用。列表(dicts)基本上是转换后的 JSON 数组
编辑 2:很抱歉没有说清楚,我会改写。
这是针对 django 数据迁移的,尽管我的问题仅适用于数据“格式化”,而不适用于框架本身或数据库插入。 我将一大堆数据作为 JSON 插入到表中以供以后分析。现在我需要对其进行规范化并正确保存。我创建了新表,需要迁移数据。
所以当我从数据库中检索数据时,我有大约 2000 个 JSON 数组。应用json.loads(arr)(通过文档)我得到了 2000 个对象列表(字典)。每个 dict 只有字符串、数字和布尔值作为每个键的值,没有嵌套的对象/数组,所以像这样:
[
{
a: 'aa',
b: 2,
c: False,
date: <date_as_long> // ex: 1471688210
},
{
a: 'bb',
b: 4,
c: True,
date: <date_as_long> // ex: 1471688210
}
]
我需要遍历每个列表并删除重复项。如果列表中除日期之外的所有字段都匹配(这不在原始问题中,因为我没有预测到),则认为某些内容是重复的。如果它们在不同的列表中匹配,则不会被视为重复。
在对内容进行更好的分析后,我发现我有接近 200 万条个人记录(而不是之前所说的 1000 万条)。
我面临的性能问题是因为每个 dict 都需要进行某种数据格式化(例如转换日期)并将其“包装”在模型对象中以进行数据库插入:ModelName(a='aaa', b=2, c=True, date=1471688210)。
数据库本身的插入是由bulk_create完成的。
注意:很抱歉未能对原始问题做出澄清。我对此进行的深入研究越多,我就越了解必须做什么以及如何处理数据。
我接受了@tuergeist 的回答,因为它指出了我需要的东西,即使我的细节不好。
鉴于 dicts 不能被散列,因此我不能将它们添加到 set() 中,我的解决方案是为重复数据创建一个 set() 元组,并用它验证重复项。如果重复项在列表中,这可以防止额外的迭代。
原来是这样的:
data = [lots of lists of dicts]
formatted_data = []
duplicates = set()
for my_list in data:
for element in my_list:
a = element['a']
b = convert_whatever(element['b'])
c = element['c']
d = (a, b, c) # Notice how only the elements that count for checking if it's a duplicate are here (not the date)
if d not in duplicates:
duplicates.add(d)
normalized_data = {
a: a,
b: b,
c: c,
date: element['date']
}
formatted_data.append(MyModel(**normalized_data)
duplicates.clear()
之后,为了更好的内存管理,我使用了生成器:
data = [lots of lists of dicts]
formatted_data = []
duplicates = set()
def format_element(el):
a = el['a']
b = convert_whatever(el['b'])
c = el['c']
d = (a, b, c)
if d not in duplicates:
duplicates.add(d)
normalized_data = {
'a': a,
'b': b,
'c': c,
'date': el['date']
}
formatted_data.append(MyModel(**normalized_data))
def iter_list(l):
[format_element(x) for x in l]
duplicates.clear()
[iter_list(my_list) for my_list in data]
这里的工作代码:http://codepad.org/frHJQaLu
注意:我完成的代码与这个有点不同(并且在功能风格上)。这只是我如何解决问题的一个例子。
编辑 3: 对于数据库插入,我使用了 bulk_create。最后,正确格式化所有内容(150 万个唯一条目,22.5 万个重复项)需要 1 分钟,将所有内容插入数据库需要 2 分钟。
谢谢大家!
【问题讨论】:
-
你能把你的问题说得更清楚些吗?你说的重复是什么意思?它们是指相同的内存位置还是副本?你说列表中的列表,所以它们像树一样。我认为时间复杂度不会低于 O(n^2)。您是在寻找一种算法还是在寻找任何现有的功能供您这样做?
-
抱歉,刚刚编辑了细节。它不是树状的,它是单独的对象列表。每个列表都有很多重复项,我需要清除它们。好吧,如果 Python 为它提供一个函数,那就更好了。但我只想以最好的方式解决问题:)
-
我不认为嵌套列表的大小使得这对于普通的 python 方法和循环来说是不可行的。如果顺序无关紧要,请使用
set(),否则请参阅:stackoverflow.com/questions/480214/…。 -
“我想这会带我永远”,“我不知道这是否可行” 如果可行,我建议您尝试其中一种方法 - 很好。如果没有,您可以在此处发布您的代码。
-
顺便说一句:我已经在从
0-100获取的 2k 个 5k 随机整数列表上尝试了list(set(..))解决方案。 timeit 模块报告 142 毫秒。如果对象不是简单的整数而是更复杂的对象,这将花费更多时间,但我仍然怀疑它会“永远”。
标签: python python-3.x