【问题标题】:Merge two lists based on condition根据条件合并两个列表
【发布时间】:2014-02-11 06:14:25
【问题描述】:

我正在尝试根据索引的位置合并两个列表,所以有点接近交叉点。

在这种情况下,集合不起作用。我要做的是匹配每个列表中的索引,然后如果该元素比其他列表中的元素少一个,那么我才会收集它。

一个例子将更好地解释我的场景。

示例输入:

print merge_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]], 
                 [[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])

样本输出:

[[0,2],[4,6]]

所以在 list1 的位置 0 上,我们有 1、3,而在 list2 中,我们有 2、6。因为 1 比 2 小一,所以我们收集它并继续前进,现在 3 小于 6,但它不是少一比即不是 5 所以我们忽略它。接下来我们有 [1, 2][1, 4],所以索引/位置都是 1,但 2 不小于 4,所以我们忽略它。接下来我们在 list2 中有 [2, 2] 两个索引 2 都不匹配第一个列表中的任何索引,所以没有比较。最后我们有 [4, 1, 3, 5] [4, 1, 6] 比较。两个索引都匹配,并且列表一中只有 5 比列表二少 1,因此我们收集了 6 个因此我们收集 [4,6] 表示索引 4 和匹配等。

我试图让它工作,但我似乎没有让它工作。

这是我目前的代码。

def merge_list(my_list1, my_list2):
merged_list = []
bigger_list = []
smaller_list = []

temp_outer_index = 0
temp_inner_index = 0  

if(len(my_list1) > len(my_list2)):
    bigger_list = my_list1
    smaller_list = my_list2
elif(len(my_list2) > len(my_list1)):
    bigger_list = my_list2
    smaller_list = my_list1
else:
    bigger_list = my_list1
    smaller_list = my_list2

for i, sublist in enumerate(bigger_list):             
    for index1 , val in enumerate(sublist):           
            for k, sublist2 in enumerate(smaller_list):
                for index2, val2 in enumerate(sublist2):                       
                    temp_outer_index = index1 + 1          
                    temp_inner_index = index2 + 1
                    if(temp_inner_index < len(sublist2) and temp_outer_index < len(sublist)):
                        # print "temp_outer:%s , temp_inner:%s, sublist[temp_outer]:%s, sublist2[temp_inner_index]:%s" % (temp_outer_index, temp_inner_index, sublist[temp_outer_index], sublist2[temp_inner_index]) 
                        if(sublist2[temp_inner_index] < sublist[temp_outer_index]):
                            merged_list.append(sublist[temp_outer_index])
                            break


return  merged_list

【问题讨论】:

  • [[1, 3], [2], [], [], [1, 3, 5]][[2, 6], [4], [2], [], [1, 6]] 作为输入会不会更有意义,所以 index 是一个实际的索引?
  • @poke,感谢您的评论。在我的其他代码中,我们构建了这些,我只构建了带有数据的代码,即没有 [] 列表。我知道它更容易制作,但不是必需的,我认为有点没有效率等。

标签: python list


【解决方案1】:

不知道你在做什么,但这应该可以。

首先,将列表列表转换为索引到该列表中包含的数字集的映射:

def convert_list(l):
    return dict((sublist[0], set(sublist[1:])) for sublist in l)

这将使列表更易于使用:

>>> convert_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]])
{0: set([1, 3]), 1: set([2]), 4: set([1, 3, 5])}
>>> convert_list([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])
{0: set([2, 6]), 1: set([4]), 2: set([2]), 4: set([1, 6])}

现在merge_lists函数可以写成这样:

def merge_lists(l1, l2):
    result = []
    d1 = convert_list(l1)
    d2 = convert_list(l2)
    for index, l2_nums in d2.items():
        if index not in d1:
            #no matching index
            continue
        l1_nums = d1[index]
        sub_nums = [l2_num for l2_num in l2_nums if l2_num - 1 in l1_nums]
        if sub_nums:
            result.append([index] + sorted(list(sub_nums)))
    return result

适用于您的测试用例:

>>> print merge_lists([[0, 1, 3], [1, 2], [4, 1, 3, 5]], 
                      [[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]]) 
[[0, 2], [4, 6]]

【讨论】:

  • 非常感谢您的帮助和回答。现在检查。
  • 使用此解决方案的大型列表的性能是二次还是线性?
  • 它是线性的。基本上你触摸所有东西的次数都是固定的。
  • 非常感谢您的时间和帮助。
  • @user3247054:当然。请问这是干什么用的?似乎很奇怪的要求
【解决方案2】:

我相信这可以满足您的要求:

import itertools

def to_dict(lst):
    dct = {sub[0]: sub[1:] for sub in lst}
    return dct

def merge_dicts(a, b):
    result = []
    overlapping_keys = set.intersection(set(a.keys()), set(b.keys()))
    for key in overlapping_keys:
        temp = [key] # initialize sublist with index
        for i, j in itertools.product(a[key], b[key]):
            if i == j - 1:
                temp.append(j)
        if len(temp) > 1: # if the sublist has anything besides the index
            result.append(temp)
    return result

dict1 = to_dict([[0, 1, 3], [1, 2], [4, 1, 3, 5]])
dict2 = to_dict([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])

result = merge_dicts(dict1, dict2)
print(result)

结果:

[[0, 2], [4, 6]]

首先,我们将您的列表转换为字典,因为它们更易于使用(这将键与其他值分开)。然后,我们查找两个 dicts 中存在的键(在示例中,这是 0、1、4),并查看每个键的两个 dicts 之间的所有值对(在示例中,1,2; 1, 6; 3,2; 3,6; 2,4; 1,1; 1,6; 3,1; 3,6; 5,1; 5,6)。每当一对的第一个元素比第二个元素小一个时,我们将第二个元素添加到我们的temp 列表中。如果 temp 列表最终包含除键之外的任何内容(即,长于 1),我们将其添加到 result 列表中,并最终返回。

(我刚想到这具有非常糟糕的性能特征 - 子列表的长度呈二次方 - 所以如果您的子列表会很长,您可能想要使用 Claudiu 的答案。如果他们将不过,简而言之,我认为初始化一个集合的成本足够大,我的解决方案可能会更快。)

【讨论】:

  • 非常感谢您的回答。现在检查。
  • 我希望我能根据很好的解释和最后一部分的表现来接受你的回答。列表会很大,因此性能确实是一个问题。与您的解决方案相比,claudiu 在性能方面的表现如何?
  • @user3247054 假设您在list1list2 中有一个具有相同索引的1000 个元素的子列表。这里的itertools.product 循环需要 1000^2 = 一百万次循环。 Claudiu 的解决方案只需要 1000 个循环(在列表理解中),而且还需要一些集合成员测试(尽管仍然只是线性数量)。你比我们更清楚你的数据是什么样子的,所以你不妨测试我们的两种解决方案,看看哪一种出来得更快。
【解决方案3】:
def merge_list(a, b):
    d = dict((val[0], set(val[1:])) for val in a)
    result = []
    for val in b:
        k = val[0]
        if k in d:
            match = [x for x in val[1:] if x - 1 in d[k]]
            if match:
                result.append([k] + match)
    return result

与其他答案类似,这将首先将其中一个列表转换为字典,其中每个内部列表的第一个元素作为键,列表的其余部分作为值。然后我们遍历另一个列表,如果第一个元素作为字典中的键存在,我们使用列表推导找到所有符合您条件的值,如果有的话,将一个条目添加到返回的 result 列表中最后。

【讨论】:

    猜你喜欢
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 2021-09-18
    • 1970-01-01
    • 2020-10-20
    相关资源
    最近更新 更多