如何在2D列表中查找与特定模式匹配的元素

问题描述

我想找到一种有效的方法来检索数组中与特定模式匹配的所有元素。

例如,考虑到我有

  • 由不同大小的子数组组成的数组M

      M = [[0,1],[3,2,4],8],[9],[0,2],3],[2,7]]
    
  • 子数组的模式。例如,[[a,b],[a,c],d]][[0,3]]匹配。

如何返回M中与模式相对应的所有元素?

到目前为止,我一直在使用for循环来查找匹配的元素,但是当模式具有两个以上的子数组时,这种幼稚的方法成本很高。

示例:

M = [[0,7]]

# pattern with 3 sub-arrays -> [[a,d]]

for i,arr1 in enumerate(M):
    for j,arr2 in enumerate(M):
        for k,arr3 in enumerate(M):
            if i != j != k:
                if len(arr1) == len(arr2) == len(arr3) == 2:
                    a1,a2,a3 = arr1[0],arr2[0],arr3[0]
                    b,c,d = arr1[1],arr2[1],arr3[1]
                    if a1 == a2 == a3 and b < c < d:
                        print arr1,arr2,arr3

输出

[0,3]
[3,7],8]

由于每个子数组都需要一个额外的嵌套循环,因此此方法的时间复杂度(O(n^k),其中k是子数组的数量)成为问题。

是否可以加快此过程?如果可以,怎么办?

解决方法

首先,在进入numpy之前,让我们看一下您的情况。您需要子数组仅包含两个元素。因此,让我们预先过滤您的数组:

M = [m for m in M if len(m) == 2]

现在您正在检查a1 == a2 == a3 and b < c < d,但是序列中会显示bcd的每个可能排列。所以说真的,如果您找到给定b != c != d任何 a,就可以将其重新排列为正确的顺序,知道该顺序最终会出现。

因此,解决此问题的一种非常简单的方法是构造一个字典映射abcd的所有可能选项,并对其进行最小过滤所需的“子数组”数量,对其进行排序,然后计算所有可能的组合:

# set removed duplicates automatically
options = collections.defaultdict(set)

for a,b in (m for m in M if len(m) == 2):  # Use a generator to filter on-the-fly
    options[a].add(b)

for a,bcd in options.items():
    # sort (combinations automatically filters too-short bins)
    for b,c,d in itertools.combinations(sorted(bcd),3):
        print(f'[{a},{b}],[{a},{c}],{d}]')

此解决方案可能在算法上是最佳的。它对初始列表进行一次遍历以识别潜在的模式,然后对每个模式执行一次精确的迭代。这里唯一可能丢失的是完全消除了重复项。您可以使用collections.Counter代替set处理重复项。