【问题标题】:compare a list to a set efficiently有效地将列表与集合进行比较
【发布时间】:2019-04-24 05:55:03
【问题描述】:

是否有更有效的方法来确保list 包含所有且仅包含set 的元素,然后从list 构造另一个set

例如避免复制和排序列表的东西

s = set([ 1, 2, 3, 4 ])
l = [ 1, 2, 3, 5 ]
if s!=set(l):
    print "bad list"

【问题讨论】:

  • 所以我假设我可以有重复。如果您真的关心不创建新对象,那么只需遍历列表并在集合中没有任何元素时使其无效。设置__contains__ 很快,但可能不会比新设置快
  • 我的意思是,这非常有效。套装非常适合比较。除非空间真的很关键,否则您的收益最多可以忽略不计。那么,空间真的那么重要吗?
  • @modesitt 我可能想允许重复。 @Paritosh 好吧,就像我说的那样,我正在寻找一种方法来避免 set 构造函数完成的复制和排序。考虑这是一个具有这些要求的理论问题。

标签: python list set compare


【解决方案1】:

您可以通过调用带有列表的集合的symmetric_difference 方法来避免从列表中构造另一个集合:

if s.symmetric_difference(l):
    print "bad list"

【讨论】:

  • 这真的不做新套装吗? seems to 从第 1716 行一目了然。你在偷偷摸摸 ;)
【解决方案2】:

如果您希望允许重复,则需要一些额外的空间来跟踪事物。然而,现在的选择可以简化为重复列表或集合的空间。如果列表通常比集合大,第一个函数可以节省一些空间。但请注意:如果集合大于列表,则会占用更多空间。

s = set([ 1, 2, 3, 4 ])
l = [ 1, 2, 3, 5 ]

方法一:按照集合的顺序创建一个Counter

def low_space_compare(some_set, some_list):        
    from collections import Counter
    state = Counter(some_set)    
    for item in some_list:
        if item not in state:
            print("bad")
            return "bad"
        state[item] -= 1
    if any(val > 0 for val in state.values()): #change to val != 0 if duplicates not allowed
        print("bad")
        return "bad"
    return "good"

另一方面,如果也不允许欺骗,您可以简单地遍历列表并从集合中删除,根本不需要额外的空间。但是它改变了集合!

方法2:没有多余的空间,不能处理欺骗

def low_space_compare_no_dupes(some_set, some_list):
    #need to create a copy of some_set if you (hopefully) take offense to mutating the original set
    for item in some_list:
        if item not in some_set:
            print("bad")
            return "bad"
        else:
            some_set.remove(item) #this makes a dupe value fail when you see it again
    if some_set:
        print("bad, set had extra stuff")
        return "bad"
    return "good"

low_space_compare(s, l) #bad
low_space_compare_no_dupes(s, l) #bad
print(s) #{4} uh oh.

编辑:方法 3:最坏的情况与从列表 n 中创建一个新集合相同,在它有效匹配但短路的情况下:

def low_space_compare_no_counters(some_set, some_list):
    new_set = set()
    #need to create a copy of some_set if you (hopefully) take offense to mutating the original set
    for item in some_list:
        if item not in some_set:
            if item not in new_set:
                print("bad")
                return "bad"
            else:
                pass #ah, a dupe, keep going           
        else:
            some_set.remove(item)
            new_set.add(item)

    if some_set:
        print("bad, set had extra stuff")
        return "bad"
    return "good"

low_space_compare_no_counters(s, l)  

【讨论】:

    猜你喜欢
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多