如何优雅地检查数组是否包含另一个数组?

3
以下是我的Python代码,用于检查大数组中的小子数组是否在其中一个子数组内。我不知道最大子数组的索引是哪个,所以无法对索引进行比较。也许对它们进行排序是一种好方法。但如果有多个大型子数组怎么办? 即我希望在最终数组中只包含包含较小子数组的大子数组。 [[1, 2, 3], [4, 5, 6], [1, 2, 3, 4, 5, 6], [7,8], [9, 10, 11, 12], [7, 8, 9, 10, 11, 12]] 其次,如果元素的顺序可以随机,该怎么办?例如: [[1, 3, 2], [4, 5, 6], [1, 2, 3, 4, 5, 6], [7,8], [9, 10, 11, 12], [7, 8, 9, 10, 11, 12]] 这是我的代码:
arr1 = [[1, 2, 3], [4, 5, 6], [1, 2, 3, 4, 5, 6], [7,8], [9, 10, 11, 12],  [7, 8, 9, 10, 11, 12]]

arr2 = []
arrInd = 0
arrInd2 = len(arr1)
for k in arr1:
    for n in reversed(arr1):
        if set(n).issubset(set(k)):
            arr2.append(k)

print(arr2)

我希望输出的结果为:[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]],但是我却得到了:[[4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [7, 8], [9, 10, 11, 12], [7, 8, 9, 10, 11, 12], [7, 8, 9, 10, 11, 12], [7, 8, 9, 10, 11, 12]] 更新
由于有很多好的问题,我需要添加更多细节。
1)有一个数组的数组: arr1 = [[]] 2)它包含了一些子数组,比如这些:[1, 2, 3],[4, 5, 6],[4, 6, 5],[7, 8, 9, 10, 11, 12],[11, 12, 13, 14, 15],[1, 2, 3, 4, 5, 6],[7, 8, 9, 10, 11, 12, 13, 14, 15],[111, 222, 333],[444, 555],[777, 888],[111, 222, 333, 444, 555],[111, 222, 333, 444, 555, 777, 888],[1000, 2000, 3000] 可能出现的情况: 1)数组内部的顺序可能会变化:[4, 5, 6], [4, 6, 5][1, 2, 3, 4, 5, 6],所以它们不是按数字顺序排列的,实际数据中(我正在测试)甚至可能会有字母,比如 A77B81; 2)有大大小小的数组,总是有一个最大的数组(或者几个),它从不与其他最大的数组相交,所以这里的 [1, 2, 3, 4, 5, 6][7, 8, 9, 10, 11, 12, 13, 14, 15] - 它们不能相互交叉,但它们包含一些小的子数组; 3)每个大的子数组都包含一些较小的子数组。但并不是所有的子数组都存在,有些小的子数组可以独立存在。例如:[1, 2, 3, 4, 5, 6] 包含 [1, 2, 3],[4, 5, 6],[4, 6, 5],但它不包含 [7, 8, 9, 10, 11, 12],[11, 12, 13, 14, 15] 或者 [111, 222, 333]; 4)还可能存在中间的“大数组”:[111, 222, 333, 444, 555] 相对于 [111, 222, 333, 444, 555, 777, 888] 来说更小,所以第一个 [111, 222, 333, 444, 555] 必须被排除。 5*)我想将大数组添加到 arr2(最终数组)中,而不包括小数组,除了情况 *** [1000, 2000, 3000],将其添加到 arr2(最终数组)中。

我的代码应该做什么?

它应该遍历arr1,并将不同的元素相对比,以便检测n元素是否包含k元素,反之亦然, 当它从开始到结束时使用for k in arr1:,当它从结尾到开头时使用for n in reversed(arr1):

更新2. 长度比较!

if len(n) < len(k):

    for k in arr1:
        for n in reversed(arr1):
            if len(n) < len(k):
                if set(n).issubset(set(k)):
                    arr2.append(k)

它非常接近,实际上几乎就是它了,但根据重复的数量来判断,似乎顺序问题(1)根本不是问题:

arr2 = [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15], [7, 8, 9, 10, 11, 12, 13, 14, 15], [111, 222, 333, 444, 555], [111, 222, 333, 444, 555], [111, 222, 333, 444, 555, 777, 888], [111, 222, 333, 444, 555, 777, 888], [111, 222, 333, 444, 555, 777, 888], [111, 222, 333, 444, 555, 777, 888]]

当然,可以开始去除重复项,再以这种方式运行arr2,以摆脱实际上是[111, 222, 333, 444, 555, 777, 888]一部分的[111, 222, 333, 444, 555],但肯定有更加优雅的方法。


3
你希望实现什么不是很清楚。 - Salvador Dali
我想在arr2中只保留那些包含较小数组的大数组。 - Anna-Lischen
1
你在问题中只给出了一个简单的例子,没有展示你想要实现的逻辑。尝试添加更多细节和输入输出的例子,特别是边缘情况。 - Reut Sharabani
1
@Alfe ReutSharabani 感谢您的评论。对于一些糟糕的描述,我很抱歉,可能是太累了。我已经更新了它,希望现在更好了))) - Anna-Lischen
1
@Alfe,请刷新页面。 - Anna-Lischen
显示剩余16条评论
5个回答

2

所以你想要摆脱那些仅包含在另一个列表中的元素的所有列表吗?

def eachMasterList(allLists):
  allSets = [ set(lst) for lst in allLists ]
  for lst, s in zip(allLists, allSets):
    if not any(s is not otherSet and s < otherSet for otherSet in allSets):
      yield lst

使用该函数,请尝试以下步骤:

print(list(eachMasterList([[1, 2, 3], [4, 5, 6], [1, 2, 3, 4, 5, 6], [7,8], [9, 10, 11, 12], [7, 8, 9, 10, 11, 12]])))

这个解决方案太棒了!对于 [[1, 2, 3], [4, 5, 6], [4, 6, 5], [7, 8, 9, 10, 11, 12], [11, 12, 13, 14, 15], [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15], [111, 222, 333], [444, 555], [777, 888], [111, 222, 333, 444, 555], [111, 222, 333, 444, 555, 777, 888], [1000, 2000, 3000]] 它给出了这个输出: [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15], [111, 222, 333, 444, 555, 777, 888], [1000, 2000, 3000]] 你真是个大师!我对自己的努力有点惭愧,但现在知道该往哪里走了。 - Anna-Lischen

1
你有一个大的列表,里面包含了很多小的列表,你想要在其中查找很多小的列表?像处理其他大型集合中的对象一样处理它们:将它们(或适当的版本)存储在集合中以实现快速查找。
列表不能作为集合元素,但你可以将小列表转换为元组并存储它们:
myindex = set(tuple(sm) for sm in big_list)

如果想要检查[1, 3, 4]是否在你的big_list中,只需要执行以下代码:

if tuple([1, 3, 4]) in myindex:
    ...

如果您想匹配无论顺序如何的列表(例如,将[1, 3, 4]视为等于[3, 1, 4]),也可以将它们转换为集合。但不是普通的集合(它们也不能成为集合元素),而是frozenset
myindex = myindex = set(frozenset(sm) for sm in big_list)

就是这样。


0
你可以使用递归函数:
>>> l =[(1, 3, 2), (4, 5, 6), (1, 2, 3, 4, 5, 6), (7, 8), (9, 10, 11, 12), (7, 8, 9, 10, 11, 12)]

>>> def find_max_sub(l):
...    for i,j in enumerate(l):
...       for t,k in enumerate(l[i+1:],1):
...             if set(j).intersection(k):
...                 return find_max_sub([set(l.pop(i))|set(l.pop(t))]+l)
...    return l
... 
>>> find_max_sub(l)
[(1, 2, 3, 4, 5, 6), (7, 8, 9, 10, 11, 12)]

你所需要做的就是循环遍历主列表,并将列表中的元素与其他元素进行比较。当你发现两个子列表有任何交集时,就弹出这些元素并将新的子列表添加到主列表中,然后使用新列表调用函数。

0

你在寻找这个吗?

def get_subset_list():
    for arr in arrays:
        others = [x for x in arrays if x != arr]
        for other in others:
            for val in arr:
                if val not in other:
                    break
            else:
                break
        else:
            yield arr

import json
x = get_subset_list()
print set([json.dumps(y) for y in x])

0
你可以将两个数组转换为字符串,然后使用__contains__进行比较。
print (''.join(arr1).__contains__(''.join(arr2)))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接