我有很多重复的对象列表(我在谈论数千个列表,每个列表包含数千个对象,占用大约1000万个单独的对象(已经没有重复)。
我需要浏览它们并删除每个列表中的所有重复项(不需要在列表之间进行比较,只需在每个列表中进行比较)。
当然,我可以浏览列表并与已经发布很多次的重复数据删除算法进行比较,但我猜这会让我永远。
我以为我可以使用精心设计的__hash__
方法创建一个对象并使用list(set(obj))
删除它们,但首先:我不知道这是否有用,第二:我还是会必须循环列表以将元素转换为新对象。
我知道Python不是我想要实现的最佳解决方案,但在这种情况下,它必须在Python中完成。我想知道以最佳性能实现这一目标的最佳途径是什么。
编辑:为了澄清:我有大约2k个对象列表,每个对象里面有大约5k个对象(粗略估计)。重复的对象是副本,而不是对同一内存位置的引用。列表(dicts)基本上是转换后的JSON数组
编辑2 :我很抱歉不清楚,我会改写。
这适用于django数据迁移,但我的问题仅适用于数据'格式化'而不是框架本身或数据库插入。 我将一大堆数据作为JSON插入到表中供以后分析。现在我需要将其标准化并正确保存。我创建了新表并需要迁移数据。
因此,当我从db检索数据时,我有大约2000个JSON数组。应用json.loads(arr)
(通过文档)我得到2000个对象列表(dicts)。每个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万个)。
我遇到的性能问题是因为每个字典都需要进行某种数据格式化(例如转换日期)和&#39; wrap&#39;它在数据库插入的模型对象中: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。最后花了1分钟正确格式化所有内容(150万个唯一条目,225k重复项)和2分钟将所有内容插入到数据库中。
谢谢大家!
答案 0 :(得分:1)
我建议有一个排序列表(如果可能的话),这样你就可以更精确地想要比较项目(就像我的意思是一个词典)。哈希(或非哈希)列表可以实现该目标。
如果您有能力管理&#34;添加和删除&#34;从你的名单中,它更好!每次添加/删除时对新项目进行排序。 (IMO很好,如果你有哈希列表,忘记你有链表)。
复杂性当然取决于你的结构(fifo / filo列表,链表,哈希......)
答案 1 :(得分:1)
以下是排序列表的解决方案:
class Solution:
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if (len(nums) == 0):
return 0;
j = 0
for i in range(len(nums)):
if (nums[i] != nums[j]):
j = j+1
nums[j] = nums[i];
return j + 1
答案 2 :(得分:0)
(可散列物品)的快速而非订单保留解决方案是
def unify(seq):
# Not order preserving
return list(set(seq))
完成修改
我假设您在dicts
内有list
。你有很多名单。从单个列表中删除重复项的解决方案是:
def remove_dupes(mylist):
newlist = [mylist[0]]
for e in mylist:
if e not in newlist:
newlist.append(e)
return newlist
此处的列表包含以下内容。 (但都是随机的)
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter","lastName":"Jones"}
运行这个,在我的MacBook(2,4GHz,i5)上花了8s用于2000 dicts
答案 3 :(得分:0)
对于复合对象(如列表中的列表),下面的代码就足够了:
def unique(a):
i = 0
while i < len(a):
p = a[i+1:]
j = 0
while j < len(p):
if p[j]!=a[i]:
j = j+1
else:
p.remove(p[j])
a = a[:i+1] + p
i = i+1
return a