Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:使用列表理解进行排序合并_Python - Fatal编程技术网

Python:使用列表理解进行排序合并

Python:使用列表理解进行排序合并,python,Python,我正在尝试将两个排序数组合并为一个排序数组。一般来说,我知道怎么做(所以问题本身不是关于合并列表),但出于学习目的,我想用列表理解来写它。理想情况下,我会这样写: i=0; j=0 [a[i++] if j >= len(b) or a[i] < b[j] else b[j++] for tmp in range (len(a)+len(b))] 但这不起作用,因为python不通过引用传递。如果我可以查看顶部元素而不推进它,我会使用迭代器,但我不能 那么,有没有一种方法

我正在尝试将两个排序数组合并为一个排序数组。一般来说,我知道怎么做(所以问题本身不是关于合并列表),但出于学习目的,我想用列表理解来写它。理想情况下,我会这样写:

i=0; j=0
[a[i++] if j >= len(b) or a[i] < b[j] else b[j++]
     for tmp in range (len(a)+len(b))]
但这不起作用,因为python不通过引用传递。如果我可以查看顶部元素而不推进它,我会使用迭代器,但我不能

那么,有没有一种方法可以把它优雅地写在一句话中,而不是像这样:

i=0; j=0
while i<len(a) or j<len(b):
    if j >= len(b) or a[i]<b[j]: res.append(a[i]); i += 1
    else res.append(b[j]); j += 1
i=0;j=0
而ii+1

j+1

如果您需要做的只是增加,而这是您遇到的唯一问题,请检查此答案

[a[i++]如果j>=len(b)或a[i]

假设i和j是带有一个元素的一维列表,如 上面的链接

使用上述函数,可以将代码转换为

[a[增量(i)]如果j>=len(b)或a[i]

更新

>>> def increment(number):
...    number[0] += 1
...    return number[0]
...
>>> num = [0]
>>> print [increment(num) for dummy in range(10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

这就是我所说的优雅:

a = [0,1,2]
b = [1,2,3]
i, j = 0, 0
result = []
for temp in range(len(a)+len(b)):
    if j>=len(b) or a[i]<b[j]:
        result.append(a[i])
        i += 1
    else:
        result.append(b[j])
        j += 1
    print(i,j,result)
print(result)
产生:

[0, 1, 1.1, 2.1, 3, 4.1, 5, 6]
它与我以前遇到的问题相同,它不从
b
收集尾随值

如果我确切知道需要多少次迭代,我也可以在列表中运行它

result = [a.pop(0) if a[0]<b[0] else b.pop(0) for _ in range(8)]

result=[a.pop(0)如果[0]我认为让列表理解在合并两个列表时起作用的唯一模糊的python方法是编写一个自定义迭代器类型,让您可以查看将要生成的下一个元素。下面是我提供的一个快速版本:

class PeekIterator(object):
    def __init__(self, iterable, sentinel=None):
        self.iterator = iter(iterable)
        self.sentinel = sentinel
        self.next_val = self.sentinel

    def peek(self):
        if self.next_val is self.sentinel:
            try:
                self.next_val = next(self.iterator)
            except StopIteration:
                pass # the sentinel will be returned if there's nothing left in the iterator
        return self.next_val

    def __iter__(self):
        return self

    def __next__(self):
        if self.next_val is self.sentinel:
           return next(self.iterator) # StopIteration is deliberately allowed to bubble out!
        val = self.next_val
        self.next_val = self.sentinel
        return val

    next = __next__ # Python 2 compatibility
现在列表变成:

a_peek = PeekIterator(a)
b_peek = PeekIterator(b)
merged = [next(a_peek) if a_peek.peek() is not None and
                          (b_peek.peek() is None or a_peek.peek() <= b_peek.peek())
          else next(b_peek)
          for _ in range(len(a) + len(b))]

我认为不理解的版本会更容易理解。

我知道这是一个很老的问题,你可能已经开始了你的生活;)但我遇到了同样的问题,并用列表理解+闭包解决了它

def merge(left, right):
    merge.lhs=0
    merge.rhs = 0
    def combine(left_side):
        if left_side:
            el = left[merge.lhs]
            merge.lhs += 1
        else:
            el = right[merge.rhs]
            merge.rhs += 1
        return el



    result =  [combine(True) if merge.rhs >= len(right) or (merge.lhs < len(left) and left[merge.lhs] < right[merge.rhs]) else combine(False) for i in range(len(left) + len(right))]

    return result

l = [1,3,5]
r = [2,4]
merge(l, r)
def合并(左、右):
merge.lhs=0
merge.rhs=0
def联合收割机(左侧):
如果是左侧:
el=左[merge.lhs]
merge.lhs+=1
其他:
el=右侧[merge.rhs]
merge.rhs+=1
返回el
结果=[如果merge.rhs>=len(右)或(merge.lhs

你可能会说这很难看,我同意,但是,我不确定使用LC是否真的可以合并两个已排序的列表!

如第二个答案中所述,使用heapq模块的合并功能可能会重复。这已经完成了你正在尝试完成的任务。这个问题还有其他几种方法可以完成它也是。请不要在一行上写多行语句,也不要在Python中使用分号。以后需要阅读您的代码的人都会感谢您。您是否尝试过
sorted(a+b)
。除非您的
a
b
非常大,否则它是O(n log n)可能不重要。例如,对于1000000个项目,
排序
需要82ms,而对于这台计算机上的
heapq.merge
需要329ms。对于1000000个项目,您的函数需要313ms。这并不能回答问题。这不是需要与列表pop()的平方时间吗方法?关于
pop
和列表上的迭代,我喜欢的一点是,我不必一直检查
len
。我只是问列表是否为空。编写正确的代码更容易。我可以用迭代器替换
pop
iter(A)
并使用
next
。您可以反转两个列表并从后面弹出。这将需要线性时间。如何反向构建列表(例如,首先生成最大结果),然后在返回之前翻转列表?
result=[];而a或b:result.append(a.pop()如果是a和(不是b或a[0]>b[0])否则b.pop();返回结果[:-1]
。这仍然是
O(N)
,而带有
pop(0)
的任何内容都将是二次的。您还需要更改
i
j
的初始化方式,以及列表理解代码的其他部分如何使用它们。
a[i]如果
i
是一个单元素列表,则
不起作用。我探索了迭代器路径,并点击了此
peek
问题。没有此额外方法,我必须维护一个单独的
当前值
变量。
result = [a.pop(0) if a[0]<b[0] else b.pop(0) for _ in range(8)]
def foo(a,b):
    result = []
    while a or b:
        if not a:
            result.extend(b)
            break
        if not b:
            result.extend(a)
            break
        x = a.pop(0) if a[0]<b[0] else b.pop(0)
        result.append(x)
    return result
class PeekIterator(object):
    def __init__(self, iterable, sentinel=None):
        self.iterator = iter(iterable)
        self.sentinel = sentinel
        self.next_val = self.sentinel

    def peek(self):
        if self.next_val is self.sentinel:
            try:
                self.next_val = next(self.iterator)
            except StopIteration:
                pass # the sentinel will be returned if there's nothing left in the iterator
        return self.next_val

    def __iter__(self):
        return self

    def __next__(self):
        if self.next_val is self.sentinel:
           return next(self.iterator) # StopIteration is deliberately allowed to bubble out!
        val = self.next_val
        self.next_val = self.sentinel
        return val

    next = __next__ # Python 2 compatibility
a_peek = PeekIterator(a)
b_peek = PeekIterator(b)
merged = [next(a_peek) if a_peek.peek() is not None and
                          (b_peek.peek() is None or a_peek.peek() <= b_peek.peek())
          else next(b_peek)
          for _ in range(len(a) + len(b))]
upper_bound = float("inf") # any value that compares larger than all the values in both of your lists
peek_a = PeekIterator(a, upper_bound)
peek_b = PeekIterator(b, upper_bound)
merged = [next(peek_a) if peek_a.peek() <= peek_b.peek() else next(peek_b)
          for _ in range(len(a)+len(b))]
def merge(left, right):
    merge.lhs=0
    merge.rhs = 0
    def combine(left_side):
        if left_side:
            el = left[merge.lhs]
            merge.lhs += 1
        else:
            el = right[merge.rhs]
            merge.rhs += 1
        return el



    result =  [combine(True) if merge.rhs >= len(right) or (merge.lhs < len(left) and left[merge.lhs] < right[merge.rhs]) else combine(False) for i in range(len(left) + len(right))]

    return result

l = [1,3,5]
r = [2,4]
merge(l, r)