所以我试着用一个例子来解释我的问题。
L1 = [0, 5, 10, 15, 20, 25]
L2 = [1, 2, 3, 4, 5, 6, 7]
L3 = [1.1, 9.5, 12, 14, 80, 90, 100]
L4 = [16, 25, 30, 40, 50, 150, 200, 250]
L5 = [15, 16, 18, 19, 29, 300, 350, 500, 600]
如果我从L1中取一个元素,我想知道L2+L3+L4+L5
中距离<1}的其他元素是否少于2个。价值(比方说1.5)。
因此,对于L1 [0] = 0:L2 [0]和L3 [0]处于距离<1。 1.5。所以没关系。 对于L1 [3] = 15:L3 [3],L4 [0],L5 [0]和L5 [1]的距离<1。 1.5 =&gt;不行
L2与L1+L3+L4+L5
等相同......我需要检查是否有任何元素接近2个以上。
我正在寻找一种快速检查这种情况的方法。我目前的方法使用列表理解,我很长,并且需要一个函数来比较2个列表,一个用于比较3,...
def duo_overlap(t1, t2):
id_t1 = [x for x in range(len(t1)) for y in range(len(t2)) if abs(t1[x] - t2[y]) < 0.3]
id_t2 = [y for y in range(len(t2)) for x in range(len(t1)) if abs(t2[y] - t1[x]) < 0.3]
return id_t1, id_t2
感谢您的建议:)
编辑:我使用时间线列表:
F20 = [0.0, 50.0, 100.0]
F40 = [0.0, 25.0, 50.0, 75.0, 100.0, 125.0]
F50 = [0.0, 20.0, 40.0, 60.0, 80.0, 100.0, 120.0, 140.0]
F100 = [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0]
F125 = [0.0, 8.0, 16.0, 24.0, 32.0, 40.0, 48.0, 56.0, 64.0, 72.0, 80.0, 88.0, 96.0, 104.0, 112.0, 120.0, 128.0, 136.0, 144.0]
设计一个的功能:
def time_builder(f, t0=0, tf=150):
return list(np.round(np.arange(t0, tf, 1/f*1000),3))
答案 0 :(得分:1)
由于每个列表都是有序的,你可以用O(nlog(n))中的堆来解决它。
基本思想是首先合并排序列表,然后将它们逐个附加到队列中,并且只保留队列中所需的元素。
def duo_overlap(*t, value): # Notice that 'keyword-only' arguments are only allowed in Python 3
num_in_queue = [0 for i in t] # the num of elements in heap of each list
iters = [0 for i in t] # what's the next element to enter the heap
min_heap = [] # a heap to get the minimum of the rest elements
queue = deque() # a queue to hold all elements (from which we can get the number of the elements) that's at a distance < value from the current element.
result = [[] for i in t]
for i in range(len(t)):
if iters[i] != len(t[i]):
heapq.heappush(min_heap, (t[i][iters[i]], i))
iters[i] += 1
while min_heap:
next_element, i = heapq.heappop(min_heap)
if iters[i] != len(t[i]): # get the next minimun element, and push the next element of the list from which the next minimun element is.
heapq.heappush(min_heap, (t[i][iters[i]], i))
iters[i] += 1
while queue and abs(queue[0][0] - next_element) >= value: # pop all elements that's at a distance >= value from the next element.
num_in_queue[queue.popleft()[1]] -= 1
result[i].append(len(queue) - num_in_queue[i]) # so you now get the number of elements that's less than and at a distance < value from the next element.
queue.append((next_element, i))
num_in_queue[i] += 1
return result
duo_overlap(time_builder(20), time_builder(40), time_builder(50), time_builder(100), time_builder(125), value=0.3)
结果是
[[0, 0, 0],
[1, 0, 1, 0, 1, 0],
[2, 0, 0, 0, 0, 2, 0, 0],
[3, 0, 1, 0, 1, 2, 1, 0, 1, 0, 3, 0, 1, 0, 1],
[4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0]]
是少于和在距离<1的元素的数量。值。
请注意,如果来自不同列表的两个元素相等,则前一个列表中的元素小于另一个元素。这只是一个技巧,不会影响结果。
您可以获得类似的功能以获得GREAT THAN,或者您可以反转列表,如
list(reversed(
list(map(
lambda t: list(reversed(t)),
duo_overlap(*list(reversed(
list(map(
lambda t: [-t[-1-i] for i in range(len(t))],
(time_builder(20), time_builder(40), time_builder(50), time_builder(100), time_builder(125))
))
)), value=0.3)
))
))
结果:
[[4, 2, 3],
[3, 0, 1, 0, 2, 0],
[2, 1, 2, 1, 2, 1, 2, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
我知道这不是很优雅,但heapq
只能使用<
构建一个堆。也许找到更好的模块是个好主意。
将两个列表一起添加,您将得到答案。
答案 1 :(得分:0)
我没有特别智能或优雅的算法,但您可以循环遍历列表。如果你聪明地做,你可以减少比较的数量(虽然整体复杂性仍然是O(n 2 ))。
def check_lists_elements(lists, margin, max_close):
# Lists with counts of close elements
counts = [[0] * len(lst) for lst in lists]
for i_lst, lst in enumerate(lists):
for i_elem, elem in enumerate(lst):
# Only check the lists after the current one to avoid repeating comparisons
for i_other_lst, other_lst in enumerate(lists[i_lst + 1:], i_lst + 1):
for i_other_elem, other_elem in enumerate(other_lst):
if abs(elem - other_elem) < margin:
# When a close pair is found increase the count for both elements
counts[i_lst][i_elem] += 1
counts[i_other_lst][i_other_elem] += 1
# Check if there are too many repetitions
if counts[i_lst][i_elem] > max_close or counts[i_other_lst][i_other_elem] > max_close:
return False
elif other_elem - elem >= margin:
# We can stop iterating after the difference is too big
break
return True
L1 = [0, 5, 10, 15, 20, 25]
L2 = [1, 2, 3, 4, 5, 6, 7]
L3 = [1.1, 9.5, 12, 14, 80, 90, 100]
L4 = [16, 25, 30, 40, 50, 150, 200, 250]
L5 = [15, 16, 18, 19, 29, 300, 350, 500, 600]
lists = [L1, L2, L3, L4, L5]
print(check_lists_elements(lists, margin=1.5, max_close=2))
>>> False