【问题标题】:Looking for unique numbers in a list of sets在集合列表中查找唯一数字
【发布时间】:2015-09-17 18:36:54
【问题描述】:

我正在运行自己的小实验,需要一些代码方面的帮助。

我正在创建一个列表,该列表在索引位置 0-99 中存储 100 个集合,每个存储的集合都存储范围从 1 到 100 的随机数,这些随机数来自包含 100 个数字的随机生成的列表。

对于每组数字,我使用 set() 命令过滤掉所有重复项,然后再将该组附加到列表中……所以基本上我有一个包含 1-100 之间数字的 100 个集合的列表。

我编写了一些代码来检查每个集合的长度 - 我注意到我的集合的长度通常为 60-69 个元素!基本上,所有数字的 1/3 是重复的。

代码:

from random import randint

sets = []

#Generate list containing 100 sets of sets.
#sets contain numbers between 1 and 100 and no duplicates.

for i in range(0, 100):
    nums = []
    for x in range(1, 101):
        nums.append(randint(1, 100))
    sets.append(set(nums))


#print sizes of each set
for i in range(0, len(sets)):
    print(len(sets[i]))


#I now want to create a final set
#using the data stored within all sets to
#see if there is any unique value.

所以这是我无法理解的一点......我想看看所有这些集合中是否有唯一的数字!我想不通的是我该怎么做。

我知道如果它们存储在自己的变量中,我可以直接将一个集合与另一个集合进行比较......但我无法找到一种有效的方法来循环遍历集合列表并将它们全部比较以创建一个新的我希望它可能只包含一个唯一值!

我在文档中看到过这段代码...

s.symmetric_difference_update(t)

但我不知道如何将它应用到我的代码中。

任何帮助将不胜感激!

【问题讨论】:

  • “唯一编号”是什么意思?你的意思是一个数字出现在所有集合中,或者一个数字是一个集合但不是任何其他集合,或者一个数字不在任何集合中?
  • 这个实验是在开始玩集合时开始的,并注意到当我循环 100 次并生成 1-100 之间的随机数时,我通常会在集合中留下大约 60-69 个唯一值.我认为看看我是否可以生成 100 个集合并将它们相互比较会很有趣。我想看看是否有一种方法可以轻松地将每个集合存储在列表中,然后遍历列表,查看每个集合以找到唯一的数字。显然,只有 1-100 范围内的几率非常低......但我想我会尝试!
  • 您指的是什么“唯一编号”?如何将这些集合相互比较?
  • 我想将所有集合减少到 1 个集合,其中包含仅出现在单个集合中的任何数字。拥有 1-100 范围内的任何数字的可能性很低,但实际上可能会出现一个数字仅生成一次的奇数时间。 - 我可以简单地使用字典来保持计数,但我想知道是否有一种方法可以使用集合来删除跨多个集合发生的所有重复项。我知道 set(list_name) 会减少列表中的所有重复项......但我想做一些类似 set(list_ contains_sets) 的事情来产生最终的集合。这有意义吗??

标签: python set


【解决方案1】:

您可以使用 Counter dict 来计算出现次数,保留所有集合中只有值 1 的值:

from collections import Counter
sets = [{randint(1, 100) for _ in range(100)} for i in range(100)]

from itertools import chain

cn = Counter(chain.from_iterable(sets))
unique = [k for k, v in cn.items() if v == 1] # use {} to get  a set
print(unique)

对于仅对任何集合唯一的元素,该元素的计数在列表中的所有集合中必须为 1。

如果我们使用一个简单的例子,我们在我们的范围之外添加一个值:

In [27]: from random import randint
In [28]: from collections import Counter  
In [29]: from itertools import chain
In [30]: sets = [{randint(1, 100) for _ in range(100)} for i in range(0, 100)]+ [{1, 2, 102},{3,4,103}]
In [31]: cn = Counter(chain.from_iterable(sets))   
In [32]: unique = [k for k, v in cn.items() if v == 1] 
In [33]: print(unique)
[103, 102]

如果您想查找包含任何这些元素的集合:

In [34]: for st in sets:
   ....:     if not st.isdisjoint(unique):
   ....:            print(st)
   ....:         
set([1, 2, 102])
set([3, 4, 103])

对于问题的编辑部分,您仍然可以使用 Counter dict 使用 Counter.most_common 来获取最小和最大出现次数:

from collections import Counter
cn = Counter()

identified_sets = 0
sets = ({randint(1, MAX) for _ in range(MAX)} for i in range(MAX))

for i, st in enumerate(sets):
    cn.update(st)
    if len(st) < 60 or len(st) > 70:
        print("Set {} Set Length: {}, Duplicates discarded: {:.0f}% *****".
              format(i, len(st), (float((MAX - len(st)))/MAX)*100))
        identified_sets += 1
    else:
        print("Set {} Set Length: {}, Duplicates discarded: {:.0f}%".
              format(i, len(st), (float((MAX - len(st)))/MAX)*100))

#print lowest fequency
comm = cn.most_common()
print("key {} : count {}".format(comm[-1][0],comm[-1][1]))

#print highest frequency
print("key {} : count {}".format(comm[0][0], comm[0][1]))

print("Count of identified sets: {}, {:.0f}%".
      format(identified_sets, (float(identified_sets)/MAX)*100))

如果您在创建此集合和您自己的代码之前调用random.seed(0),您将看到它们都返回相同的数字。

【讨论】:

    【解决方案2】:

    你可以这样做:

    result = set()
    for s in sets:
        result.symmetric_difference_update(s)
    

    【讨论】:

    • 糟糕,这实际上是错误的。看看what it gives you 的三组 - 这不是正确的。
    【解决方案3】:

    在浏览完这些 cmets 之后,我决定做一些不同的事情来实现我的目标。本质上,我意识到我只是想在删除所有重复项后检查随机数生成器生成的数字的频率。我以为我可以通过使用集合来删除重复项,然后使用集合来删除集合中发现的重复项来做到这一点……但这实际上不起作用!!

    我还注意到,在 100 个集合中最多包含 100 个可能的数字,平均而言,重复数字的数量约为 30-40%。随着您增加最大集合数,从而增加生成的最大数字数量,丢弃的重复数字的百分比以明显的模式减少。

    经过进一步调查,您可以计算出丢弃数字的百分比 - 这完全取决于生成数字后命中相同数字的概率...

    无论如何...谢谢您的帮助!

    代码更新:

    from random import randint
    
    sets = []
    identified_sets = 0
    
    MAX = 100
    
    for i in range(0, MAX):
        nums = []
        for x in range(1, MAX + 1):
            nums.append(randint(1, MAX))
        nums.sort()
        print("Set %i" % i)
        print(nums)
        print()
        sets.append(set(nums))
    
    
    for i in range(0, len(sets)):
        #Only relevant when using MAX == 100
        if len(sets[i]) < 60 or len(sets[i]) > 70:
            print("Set %i Set Length: %i, Duplicates discarded: %.0f%s *****" %
                  (i, len(sets[i]), (float((MAX - len(sets[i])))/MAX)*100, "%"))
            identified_sets += 1
        else:
            print("Set %i Set Length: %i, Duplicates discarded: %.0f%s" %
                  (i, len(sets[i]), (float((MAX - len(sets[i])))/MAX)*100, "%"))
    
    
    #dictionary of numbers
    count = {}
    for i in range(1, MAX + 1):
        count[i] = 0
    
    #count occurances of numbers
    for s in sets:
        for e in s:
            count[int(e)] += 1
    
    
    #print lowest fequency
    print("key %i : count %i" %
          (min(count, key=count.get), count[min(count, key=count.get)]))
    
    #print highest frequency
    print("key %i : count %i" %
          (max(count, key=count.get), count[max(count, key=count.get)]))
    
    #print identified sets <60 and >70 in length as these appear less often
    print("Count of identified sets: %i, %.0f%s" %
          (identified_sets, (float(identified_sets)/MAX)*100, "%"))
    

    【讨论】:

      【解决方案4】:

      您也可以保留反转矩阵,它是从数字到该数字所在的集合索引集的映射。这个映射应该是一个普通的字典(从数字到集合),但是一个简单的列表of sets 可以在这里解决问题。 (我们也可以使用 Counter,而不是保留整个反转矩阵)

      from random import randint
      
      sets = [set() for _ in range(100)]
      byNum = [set() for _ in range(100)]
      
      #Generate list containing 100 sets of sets.
      #sets contain numbers between 1 and 100 and no duplicates.
      
      for setIndex in range(0, 100):
          for numIndex in range(100):
              num = randint(1, 100)
              byNum[num].add(setIndex)
              sets[setIndex].add(num)
      
      
      #print sizes of each set
      for setIndex, _set in enumerate(sets):
          print(setIndex, len(_set))
      
      #I now want to create a final set
      #using the data stored within all sets to
      #see if there is any unique value.
      
      for num, setIndexes in enumerate(byNum)[1:]:
          if len(setIndexes) == 100:
              print 'number %s has appeared in all the random sets'%num
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-07
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        • 2017-03-19
        • 1970-01-01
        • 2021-09-24
        相关资源
        最近更新 更多