【问题标题】:How to find elements that match a specific pattern in a 2d list如何在二维列表中查找与特定模式匹配的元素
【发布时间】:2021-01-11 03:57:06
【问题描述】:

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

例如,考虑到我有:

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

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

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

到目前为止,我一直在使用 for 循环来查找匹配元素,但是当模式具有超过 2 个子数组时,这种幼稚的方法变得非常昂贵。

例子:

M = [[0, 1], [3, 2, 4], [3, 8], [9], [0, 2], [3, 1], [0, 3], [2, 4], [3, 7]]

# pattern with 3 sub-arrays -> [[a, b], [a, c], [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,1], [0,2], [0,3]
[3,1], [3,7], [3,8]

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

是否可以加快这个过程?如果有,怎么做?

【问题讨论】:

  • 这几乎与numpy无关。 Numpy 不允许参差不齐的数组。
  • 我不太明白你在用这个模式做什么。如果你遇到一个只有一个元素的子数组会发生什么?
  • 用“if len(arr) == 2”过滤掉。如何使子数组具有相同的大小,例如用 NaN 填充它们。 == 的条件语句应该仍然有效。
  • 如果你做一个不参差不齐的数组,实际使用numpy,并正确地进行向量化,你会看到速度有巨大的提升
  • [3, 1], [3, 7], [3, 8] 怎么匹配?​​

标签: python optimization pattern-matching


【解决方案1】:

首先,在进入 numpy 之前,让我们来看看你的条件。您要求子数组只有两个元素。所以让我们预先过滤你的数组:

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

现在您正在检查a1 == a2 == a3 and b &lt; c &lt; 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}], [{a}, {d}]')

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

【讨论】:

  • 您的回答专门解决了这种模式,但未能提供解决问题的一般方法(如果模式是 [[1,2,3] [4,5,6], [1,4 ]] 或只是 [[1, 2, 3]] ?)。我的问题很可能没有很好地表述或充其量是不完整的。我接受这个答案,稍后会尝试提出一个更好、更清晰和有据可查的问题。感谢您的宝贵时间。
  • @solub。如果您想出更通用的模式表述,请随时联系我。这是一个有趣的问题。正如您所注意到的,如果不说明您的意图,我无法编写更通用的解决方案。
猜你喜欢
  • 2014-11-04
  • 2016-04-28
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多