将多个列表合并为一个大列表,并移动元素

merging multiple lists with shifting elements into one big list

提问人:Harris 提问时间:7/26/2023 最后编辑:Harris 更新时间:7/29/2023 访问量:42

问:

如何合并/扩展列表以将元素包含在另一个包含更多信息的列表中?问题在于发生偏移的索引不是恒定的。

[1,2,3,4], [2,3,4,5], [5,6,7,8], [7,8,9,10][1,2,3,4,5,6,7,8,9,10]

列表是时间序列的定时快照,因此元素的顺序和顺序应保持不变,并且允许重复元素,即[1,2,3,4,5,5,6,7,8] [4,5,5,6,7,8,9,10,11]

第二个列表包含第一个列表中的元素以及更多元素,您可以说第二个列表与第一个列表相同,但它已向左移动并添加了更多元素。

例如

l1 = [1,2,3,4,5,5,6,7,8]

l2 = [4,5,5,6,7,8,9,10,11]

结果为

l3 = [1,2,3,4,5,5,6,7,8,9,10,11]

python 数组 列表 序列 组合并

评论


答:

0赞 Zero 7/26/2023 #1

根据您的第二个示例,甚至允许重复。因此,您可以使用字典来跟踪第一个列表中的元素及其计数,并将其与第二个列表进行比较并相应地附加/更新。

l1 = [1,2,3,4,5,5,6,7,8]
l2 = [4,5,5,6,7,8,9,10,11]

lookup = {}

for elem in l1:
    if elem in lookup:
        lookup[elem] += 1

    else:
        lookup[elem] = 1

for elem in l2:
    if elem in lookup and lookup[elem] > 0:
        lookup[elem] -= 1

    else:
        l1.append(elem)

print(l1)

输出:

[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11]
0赞 Andrej Kesely 7/26/2023 #2

IIUC,您可以尝试(基于“第二个列表与第一个列表相同,但它已向左移动并添加了更多元素”的假设):

l1 = np.array([1,2,3,4,5,5,6,7,8])
l2 = np.array([4,5,5,6,7,8,9,10,11])

idx = np.searchsorted(l1, l2[0])
out = np.hstack([l1[:idx], l2])
print(out)

指纹:

[ 1  2  3  4  5  5  6  7  8  9 10 11]

评论

1赞 Alain T. 7/29/2023
当拆分发生在重复值上时,直接二进制搜索不会涵盖某些边缘情况。例如,应该输出,但你得到.[1,2,3,4,4,5,5,6,7,8] and [4,5,5,6,7,8,9,10,11][1 2 3 4 4 5 5 6 7 8 9 10 11][ 1 2 3 4 5 5 6 7 8 9 10 11]
1赞 M Germanos 7/26/2023 #3

您可以检查 l1 的结束子列表,并将它们与 l2 的开头进行比较。如果它们匹配,则合并它们。

def merge_series(l1,l2):
    
    for i in range(len(l1)):

        #check if the end sub-list of l1 matches the beginning sublist of l2 for this index
        if l1[i:] == l2[:(len(l1)-i)]:
            #marge them if they do
            l1.extend(l2[(len(l1)-i):])
            return l1
    # there is no match, just merge lists
    l1.extend(l2)
    return l1
1赞 Alain T. 7/29/2023 #4

您可以使用 next 函数来标识第一个列表中不再位于第二个列表开头的部分,并添加相应的下标以形成第三个列表:

l1 = [1,2,3,4,5,5,6,7,8]

l2 = [4,5,5,6,7,8,9,10,11]

start = l1.index(l2[0]) if l2[0] in l1 else len(l1)
keep  = next(i for i in range(start,len(l1)+1) if l1[i:] == l2[:len(l1)-i])

l3   = l1[:keep] + l2

print(l3)
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11]

为了加快速度,可以使用二进制搜索来识别起点。由于重复,它无法提供精确的范围,但如果列表非常大,它可能会减少获取起始位置所需的时间:

from bisect import bisect_left

l1 = [1,2,3,4,4,5,5,6,7,8]
l2 = [4,5,5,6,7,8,9,10,11]

start = bisect_left(l1,l2[0])
keep  = next(i for i in range(start,len(l1)+1) if l1[i:] == l2[:len(l1)-i])
l3    = l1[:keep]+l2

print(l3)
[1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11]