如何有效地保留外连接两个排序列表

时间:2014-10-15 20:54:26

标签: python algorithm

我有两个已经排序的列表。我需要离开外部加入他们。以下代码完成了工作:

left_sorted_list = [1, 2, 3, 4, 5]
right_sorted_list = [[2, 21], [4, 45], [6, 67]]
right_dict = {r[0]: r[1] for r in right_sorted_list}
left_outer_join = [[l, right_dict[l] if l in right_dict.keys() else None]
                   for l in left_sorted_list]
print(left_outer_join)
[[1, None], [2, 21], [3, None], [4, 45], [5, None]]

但是,我不确定这种方法是否非常有效。是否有更有效的方法来利用正确列表已经排序的事实,而不编写循环?

修改我加入的密钥在左侧和右侧列表中都是唯一的。

3 个答案:

答案 0 :(得分:4)

这是一个内存效率高的版本,可以一次生成一个键/值对:

def left_outer_join(keys, pairs, default=None):
    right = iter(pairs)
    right_key = float('-inf') # sentinel: any left key must be larger than it
    for left_key in keys:
        if left_key == right_key: # *keys* and *right* are in sync
            value = right_value  # from previous iteration
        elif left_key < right_key: # *keys* is behind *right*
            value = default
        else: # left_key > right_key: *keys* is ahead of *right*
            for right_key, right_value in right: # catch up with *keys*
                if left_key <= right_key: # drop while left_key > right_key
                    break
            value = right_value if left_key == right_key else default
        yield left_key, value

O(n+m)单通算法。

示例:

left_sorted_list = [1, 2, 3, 4, 5]
right_sorted_list = [[2, 21], [4, 45], [6, 67]]
print(list(left_outer_join(left_sorted_list, right_sorted_list)))
# -> [(1, None), (2, 21), (3, None), (4, 45), (5, None)]

keyspairs可以是相应的键和键/值对的无限排序迭代器(例如由heapq.merge()函数生成)。

答案 1 :(得分:3)

这个答案直接取决于mgilson对OP问题的两条评论。

这并不比你拥有的效率高,但它更具有pythonic。

left_sorted_list = [1, 2, 3, 4, 5]
right_sorted_list = [[2, 21], [4, 45]]

right_dict = dict(right_sorted_list)
left_outer_join = [[l, right_dict.get(l)] for l in left_sorted_list] 

就时间复杂度而言,left_sorted_listright_sorted_list每次迭代一次,因此它们都是O(N)。对于字典查找the average look-up is O(1),所以查找所有键也是O(N)。你的时间复杂性不会比现有的好多少。

答案 2 :(得分:1)

对于结果我使用了元组,因此方括号较少;)

left_sorted_list = [1, 2, 3, 4, 5]
right_sorted_list = [[2, 21], [4, 45]]

d  = dict(right_sorted_list) # if you have a list of pairs, just pass it to dict()
print [(x, d[x] if x in d else None) for x in left_sorted_list]

## -- End pasted text --
[(1, None), (2, 21), (3, None), (4, 45), (5, None)]