我有两个列表。两者都是数字排序列表。说:
A = [1.1, 5.2, 12.3, 12.6]
B = [2.3, 2.7, 5.2, 11.1, 12.1, 15.6, 16.6]
在这种情况下,我想输出:
result = [[2.3], [0.4, 2.5], [5.9, 1]]
和一个附加列表:
remainder = [3.5, 1]
首先考虑B中连续值之间的差异列表,并在开头添加一个隐式零。
[2.3, 0.4, 2.5, 5.9, 1, 3.5, 1]
我们需要根据A中每个值最接近B中的位置进行拆分。
对于A中的每个数字,B中最接近的值为:
1.1 -> 2.3 -> 2.3
5.2 -> 5.2 -> 2.5
12.3 -> 12.1 -> 1
12.6 -> 12.1 -> 1
其余的进入剩余变量。
我正在寻找一种快速(线性时间)的方式在python中做到这一点。任何帮助,非常感谢。我不介意它是否使用numpy,以较快者为准。
我的尝试:
我试图解决这个问题,但是要通过复杂的途径。首先,我使用以下方式进行映射:
def find_nearest(array, value):
idx = np.searchsorted(array, value, transformed_remainderside="left")
if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
return array[idx-1]
else:
return array[idx]
然后我用它来制作:
[[2.3], [2.7, 5.2], [11.1, 12.1]] and [15.6, 16.6]
然后我做
[[2.3], [0.4, 2.9], [5.9, 6.9]] and [3.5, 4.5]
然后我最终得到[[2.3],[0.4、2.5],[5.9、1]]和[3.5、1]
这很痛苦且容易出错,而且总体上也不是线性时间。
A = [2.3, 2.7, 5.2, 11.1]
B = [2.3, 2.7, 5.2, 11.1]
result = [[2.3], [0.4], [2.5], [5.9]]
remainder = []
答案 0 :(得分:1)
这可以通过将任务分为两部分来以非常明确的方式完成:匹配最接近的数字并建立范围。
首先,代码线性地遍历两个数组,并为A中的每个数字选择B中最接近的数字。然后,代码将结构转换为所需的相邻数字范围的输出,并滤除不匹配的范围:
import numpy as np
A = [1.1, 5.2, 12.3, 12.6]
B = [2.3, 2.7, 5.2, 11.1, 12.1, 15.6, 16.6]
# This array will hold the closest numbers in A for each number in B
matches = [[] for _ in B]
i = 0
for num in A:
# Check if the current number in B is the closest to the current one
# This assumes both arrays are sorted
while i < len(B) - 1 and abs(num - B[i]) > abs(num - B[i + 1]):
i += 1
matches[i].append(num)
# Unite the pairs so each range has a list of matching numbers
matches = [[matches[0]]] + [l1+l2 for l1, l2 in zip(matches[1::2], matches[2::2])]
# Create a list of diffs and pair them into ranges
diffs = (np.array(B[1:]) - np.array(B[:-1])).tolist()
ranges = [[B[0]]] + list(map(list, zip(diffs[::2], diffs[1::2])))
# Output only the ranges that had at least a single match in A
ranges_with_numbers = [num_range for num_range, range_matches in zip(ranges, matches)
if len(range_matches) > 0]
remainder = [num_range for num_range, range_matches in zip(ranges, matches)
if len(range_matches) == 0]
复杂度为 O(n),因为匹配阶段仅扫描每个数组一次,变换阶段也是如此。
答案 1 :(得分:1)
这里是基于[np.searchsorted
]-
# https://stackoverflow.com/a/45350318/ Variant for already sorted B
def closest_argmin_sortedB(A, sorted_B):
L = len(sorted_B)
sorted_idx = np.searchsorted(sorted_B, A)
sorted_idx[sorted_idx==L] = L-1
mask = (sorted_idx > 0) & \
((np.abs(A - sorted_B[sorted_idx-1]) < np.abs(A - sorted_B[sorted_idx])) )
return sorted_idx-mask
A = np.asarray(A)
B = np.asarray(B)
d = np.ediff1d(B,to_begin=B[0])
idx = closest_argmin_sortedB(A,B)
idxf = idx[np.r_[True,idx[:-1]!=idx[1:]]]
p = np.split(d,idxf+1)
res,remainder = p[:-1],p[-1]
在更大的列表上,要实现性能提升,我们可以使用zip进行切片,从而分割数组/列表数据。因此,最后两个步骤可以替换为-
s = np.r_[0,idxf+1,len(d)]
res,remainder = [d[i:j] for (i,j) in zip(s[:-2],s[1:-1])], d[s[-2]:s[-1]]