试图从大型对象列表中删除重复项,保留一定的对象

时间:2016-02-04 00:09:36

标签: python

我在Python中有一个很大的对象列表,我将其存储在一个文本文件中(由于缺乏如何使用任何其他数据库的知识)。

目前有40,000个但我希望列表长度最终可能超过1,000,000。我正在尝试删除重复项,其中重复项被定义为具有相同文本字符串属性值的不同对象,但保留该对象的最新版本(定义为在另一个属性中具有最高值)。

我想要的是一个函数,它可以可靠地返回以下列表中的对象2和3:

Object 1: text="hello"            ID=1
Object 2: text="hello"            ID=2
Object 3: text="something else"   ID=3

手动执行此操作(每次为每个对象循环遍历列表)已经太慢了,O(l^2)会变慢,所以我需要一种更聪明的方法来完成它。我已经看过散列对象并使用多次推荐的set函数,但我有两个问题,我没有找到满意的答案:

  1. 散列如何提高效率达到它的程度?

  2. 如何执行此操作并仅保留最新的此类对象?我看到的例子都使用了set函数,我不确定它是如何只返回最近的函数。

  3. 编辑:我可能在其他地方找到问题1的好答案,但我仍然坚持问题2.要再次尝试解释它,在其文本上散列上面的对象并使用set函数将返回一个集合从每个重复组中随机选择从重复项中选择的对象(例如,上面,可以返回一组(对象2,对象3)或(对象1,对象3);我需要(对象2,对象3) )。

3 个答案:

答案 0 :(得分:1)

更改为使用数据库...

import sqlite3
db = sqlite3.connect("my.db")
db.execute("CREATE TABLE IF NOT EXISTS my_items (text PRIMARY KEY, id INTEGER);")
my_list_of_items = [("test",1),("test",2),("asdasd",3)]
db.execute_many("INSERT OR REPLACE INTO my_items (text,id) VALUES (?,?)",my_list_of_items)
db.commit()

print(db.execute("SELECT * FROM my_items").fetchall())

这在时间上可能会有更高的开销......但你会保存在RAM中

答案 1 :(得分:0)

Hashing是计算机科学中一门经过深入研究的课程。其中一个标准用途是实现Python调用dictionary的内容。 (出于某种原因,Perl将hash称为同一事物。;-))

这个想法是,对于某些键,例如字符串,您可以计算一个简单的数字函数 - 哈希值 - 并使用该数字作为查找存储的相关值的快速方法在字典里。

Python具有内置函数hash(),它返回此值的标准计算。对于希望计算自己的哈希值的对象,它还支持__hash__()函数。

在“正常”场景中,确定您之前是否看过字段值的一种方法是将字段值用作字典的一部分。例如,您可能存储了一个字典,该字典将相关字段映射到整个记录,或者存储所有共享相同字段值的记录列表。

在您的情况下,您的数据太大(根据您而定),因此这不是一个坏主意。相反,你可以尝试这样的事情:

seen_before = {}    # Empty dictionary to start with.

while ... something :
    info = read_next_record()   # You figure this out.
    fld = info.fields[some_field]  # The value you care about

    hv = hash(fld)     # Compute hash value for field.

    if hv in seen_before:
        print("This field value has been seen before")

    else:
        seen_before[hv] = True  # Never seen ... until NOW!

答案 2 :(得分:0)

可以使用带有文本键的dict和每个键的最新对象作为值。

设置一些演示数据:

>>> from collections import namedtuple
>>> Object = namedtuple('Object', 'text ID')
>>> objects = Object('foo', 1), Object('foo', 2), Object('bar', 4), Object('bar', 3)

解决方案:

>>> unique = {}
>>> for obj in objects:
        if obj.text not in unique or obj.ID > unique[obj.text].ID:
            unique[obj.text] = obj

>>> unique.values()
[Object(text='foo', ID=2), Object(text='bar', ID=4)]