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] |
遍历
注意:我希望尽可能有效地避免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]) |
很简单,但是如果
当你定义"近似"时,你可以开始正确地思考一个解决方案。
如果列表是预先排序的,那么提到它将是一件很有帮助的事情。
这应该给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中的两个数字匹配(反之亦然),则此代码将只报告一个匹配。