在集合列表中寻找唯一数字

Looking for unique numbers in a list of sets

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

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

对于每组数字,我使用 set() 命令在将这组数字附加到列表之前过滤掉任何重复项...所以基本上我有一个包含 100 组数字的列表,其中包含 1-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)

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

任何帮助将不胜感激!!

你可以做到:

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

你也可以保留反转矩阵,它是从数字到该数字所在的集合索引集的映射。这个映射在一般情况下应该是一个字典(从数字到集合),但是简单的集合列表可以在这里解决问题。 (我们也可以使用 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

您可以使用 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.most_common 的 Counter dict 来获取最小和最大出现次数:

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),您将看到它们 return 相同的数字。

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

我还注意到,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, "%"))