关于python:比较2个列表以查找相等或近似匹配而不进行N ^ 2迭代

Compare 2 lists to find an equal or approximate match without doing N^2 iteration

我有两个列表:

1
2
list1 = [101, 110, 136]
list2 = [101.04, 264.5, 379.9, 466.4, 629.6, 724.4, 799.8, 914.3]

遍历list1并将此列表中的每个元素与list2中的元素进行比较。如果在第二个列表中遇到一个与list1中的元素完全匹配或近似匹配的数字,则输出该匹配。

注意:我希望尽可能有效地避免n^2迭代


结果发现这个问题有点棘手。下面的代码应该适用于任何数据集和利润值,但我没有广泛测试过它。

避免O(n^2)性能的唯一方法是对数据进行排序,这样可以使用两个索引值,这样您就可以以与第一个索引值不同的速度浏览第二个列表,并且仍然可以进行有效的比较。

下面的代码将为列表1中的每个项目打印出列表2中的每个匹配项,因此打印可能有一些重复项,因此性能将略低于O(N),但在较小的页边距下会更好。(这里选择的大范围放大设置高或低的效果)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
list1 = [101, 110, 136, 380]
list2 = [101.04, 110.009, 264.5, 379.9, 466.4, 629.6, 724.4, 799.8, 914.3]
#guarantee that lists are sorted
list1.sort()
list2.sort()
#Set margin differently as needed
margin = 100
idx = 0;
for i in list1:
    while i > list2[idx] and not abs(i - list2[idx]) <= margin:
        idx+=1
    tempIdx = idx
    #Print out all the elements in list2 that are within the margin for list1
    while abs(i - list2[tempIdx]) <= margin:
        print list2[tempIdx]
        tempIdx+=1

你考虑过近似的意思吗?

1
2
3
4
>>> list1 = [101, 110, 136]
>>> list2 = [101.04, 264.5, 379.9, 466.4, 629.6, 724.4, 799.8, 914.3]
>>> set(int(x) for x in list1) & set(int(x) for x in list2)
set([101])

很简单,但是如果list2[100.96, 264.5, 379.9, ...你就得不到匹配

当你定义"近似"时,你可以开始正确地思考一个解决方案。

如果列表是预先排序的,那么提到它将是一件很有帮助的事情。


这应该给O(nlogn)时间(因为有两种类型),具有用户指定的公差epsilon。它松散地基于mergesort的合并步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/local/cpython-3.3/bin/python

import pprint

def approximate_matches(list1, list2, epsilon = 0.5):
    len_list1 = len(list1)
    len_list2 = len(list2)

    list1_index = 0
    list2_index = 0

    while list1_index < len_list1 and list2_index < len_list2:
        list1_element = list1[list1_index]
        list2_element = list2[list2_index]

        difference = abs(list1_element - list2_element)

        if difference < epsilon:
            yield (list1_element, list2_element)
            list1_index += 1
            list2_index += 1
        elif list1_element < list2_element:
            list1_index += 1
        elif list2_element < list1_element:
            list2_index += 1
        else:
            raise AssertionError('Unexpected else taken')


def main():
    list1 = [101.0, 110.0, 136.0, 379.6, 800.0, 900.0]
    list2 = [101.04, 264.5, 379.9, 466.4, 629.6, 724.4, 799.8, 914.3]

    list1.sort()
    list2.sort()

    pprint.pprint(list(approximate_matches(list1, list2)))

main()

高温高压

注意,如果列表1中的一个数字与列表2中的两个数字匹配(反之亦然),则此代码将只报告一个匹配。