簡體   English   中英

如何刪除Python中巨大的對象列表的重復項

[英]How to remove duplicates of huge lists of objects in Python

我有很多重復的對象列表(我說的是數千個列表,每個列表包含數千個對象,占用大約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萬個)。 我遇到的性能問題是因為每個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。 最后花了1分鍾正確格式化所有內容(150萬個唯一條目,225k重復項)和2分鍾將所有內容插入數據庫。

謝謝你們!

我建議有一個排序列表(如果可能的話),這樣你就可以更精確地想要比較項目(就像我的意思是一個詞典)。 哈希(或非)列表可以實現該功能。

如果您能夠管理列表中的“添加和刪除”,那就更好了! 每次添加/刪除時對新項目進行排序。 (IMO很好,如果你有哈希列表,忘記你有鏈表)。

復雜性當然取決於你的結構(fifo / filo列表,鏈表,哈希...)

(可洗物品)的快速而非訂單保留解決方案是

def unify(seq):
    # Not order preserving
    return list(set(seq))

完成編輯

我假設你在listdicts 你有很多名單。 從單個列表中刪除重復項的解決方案是:

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

完整代碼: http//pastebin.com/NSKuuxUe

以下是排序列表的解決方案:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM