Python:只设置存在检查?

时间:2009-08-26 09:13:45

标签: python data-structures hash set

我有一些很长的大字符串,我想要查找它们。我不需要保存整个字符串。据我所知,set()实际存储的字符串占用了我很多的记忆。

是否存在这样的数据结构?

done = hash_only_set()
while len(queue) > 0 :
   item = queue.pop()
   if item not in done :
      process(item)
      done.add(item)

(我的队列不断被其他线程填充,所以我无法在开始时重复删除它。)

6 个答案:

答案 0 :(得分:10)

当然可以保留一组唯一的哈希值:

done = set()
while len(queue) > 0 :
   item = queue.pop()
   h = hash(item)
   if h not in done :
      process(item)
      done.add(h)

请注意,由于哈希冲突,您可能会认为项目已完成,即使它不是。

如果你不能接受这种风险,你真的需要保存完整的字符串,以便能够判断你以前是否已经看过它。或者:也许处理本身可以告诉?

另外,如果您不能接受将字符串保留在内存中,请将它们保存在数据库中,或者在与该字符串同名的目录中创建文件。

答案 1 :(得分:4)

您可以专门为此目的使用名为Bloom Filter的数据结构。可以找到Python实现here

编辑:重要提示:

  1. 此数据结构中可能存在误报 ,即检查字符串是否存在可能会返回正结果,即使它 存储。
  2. 不能使用假阴性(获得存储的字符串的否定结果)。
  3. 尽管如此,如果使用得当,可以将发生这种情况的可能性降到最低,因此我认为这种数据结构非常有用。

答案 2 :(得分:4)

如果您使用安全(如在hashlib模块中找到的SHA-256)散列函数来散列字符串,那么您发现重复的可能性很小(如果您找到一些,则可能会赢得一个奖励与大多数加密哈希函数一样)。

内置__hash__()方法不保证你不会有重复项(因为它只使用32位,你很可能会找到一些)。

答案 3 :(得分:3)

您需要知道整个字符串才能100%确定。如果你有很多带有类似前缀的字符串,你可以通过使用trie来存储字符串来节省空间。如果您的字符串很长,您还可以通过使用像SHA-1这样的大型哈希函数来节省空间,从而使哈希冲突的可能性变得如此遥远以至于无关紧要。

如果你可以使process()函数具有幂等性 - 即在项目上调用两次只是一个性能问题,那么问题会变得简单得多,你可以使用有损数据结构,例如布隆过滤器。 / p>

答案 4 :(得分:2)

您必须考虑如何进行查找,因为该集需要两种方法,__hash____eq__

哈希是一个可以带走的“松散部分”,但__eq__不是一个可以保存的松散部分;你必须有两个字符串进行比较。

如果您只需要否定确认(此项目不是该项目的一部分),您可以填充您自己用字符串实现的Set集合,然后通过删除所有字符串来“完成”该集合,除了那些有冲突的字符串(那些被保留在 eq 测试中,并且您保证不会向您的Set中添加更多对象。现在你有一个独家测试..你可以判断你的Set中的对象是不是。如果“Set == True”中的obj是否为误报,则无法确定。

编辑:这基本上是一个巧妙地链接的布隆过滤器,但布隆过滤器可能会为每个元素使用多个散列,这非常聪明。

Edit2:这是我的3分钟布隆过滤器:

class BloomFilter (object):
    """ 
    Let's make a bloom filter
    http://en.wikipedia.org/wiki/Bloom_filter

    __contains__ has false positives, but never false negatives
    """ 
    def __init__(self, hashes=(hash, )): 
        self.hashes = hashes
        self.data = set()
    def __contains__(self, obj):
        return all((h(obj) in self.data) for h in self.hashes)
    def add(self, obj):
        self.data.update(h(obj) for h in self.hashes)

答案 5 :(得分:0)

正如已经暗示的那样,如果这里提供的答案(大多数在哈希冲突面前崩溃)都是不可接受的,那么你需要使用字符串的无损表示。

Python的zlib模块提供了内置的字符串压缩功能,可以在将字符串放入集合之前用于预处理字符串。但请注意,字符串需要很长(你暗示它们是这样)并且具有最小的熵以节省大量内存空间。其他压缩选项可以提供更好的空间节省,并且可以找到一些基于Python的实现here