用于单步通过两个列表并避免idx的Python风格?

用于单步通过两个列表并避免idx的Python风格?,python,Python,(在我开始之前,让我们先假设这是一个面试问题,我的目的是避免仅仅打电话。) 我的Python代码如下: def merge_sorted_lists(left, right): leftlen = len(left) rightlen = len(right) leftidx = 0 rightidx = 0 newlist = [] while leftidx < leftlen or rightidx < rightlen:

(在我开始之前,让我们先假设这是一个面试问题,我的目的是避免仅仅打电话。)

我的Python代码如下:

def merge_sorted_lists(left, right):
    leftlen = len(left)
    rightlen = len(right)
    leftidx = 0
    rightidx = 0
    newlist = []
    while leftidx < leftlen or rightidx < rightlen:
        if rightidx == rightlen or left[leftidx] <= right[rightidx]:
            newlist.append(left[leftidx])
            leftidx += 1
        elif leftidx == leftlen or right[rightidx] < left[leftidx]:
            newlist.append(right[rightidx])
            rightidx += 1
    return newlist
def merge_sorted_列表(左、右):
leftlen=len(左)
rightlen=len(右)
leftidx=0
rightidx=0
新列表=[]
当leftidx如果rightidx==rightlen或left[leftidx]呃,首先,我会尝试使用生成器。我使用的是收益率而不是构建一个列表,因为a)生成器可以是无限的,b)嘿,一旦你开始使用生成器,也可以一直使用生成器

def merge(left,right): 
    left = iter(left)
    right = iter(right)
    left_val = next(left)
    right_val = next(right)
    try:
        while True:
            if left_val <= right_val:
                yield left_val
                left_val = next(left) #left.next() in python2
            else:
                yield right_val
                right_val = next(right)
    except StopIteration: #I have exhausted one of the iterators
        if left_val <= right_val:
            #left list depleted
            yield right_val
            for i in right: yield i #or use yield from right, if your python is fancy enough
        else:
            #right list depleted
            yield left_val
            for i in left: yield i 

我可能会为此创建一个合并生成器:

def merge_generator(llist, rlist):
    while len(llist) + len(rlist) > 0:
        if len(llist) == 0:
            yield rlist[0]
            rlist = [1:]
        elif len(rlist) == 0:
            yield llist[0]
            llist = [1:]
        else:
            if llist[0] < rlist[0]:
                yield rlist[0]
                rlist = rlist[1:]
            else:
                yield llist[0]
                llist = llist[1:]
def合并生成器(llist、rlist):
而len(llist)+len(rlist)>0:
如果len(llist)==0:
收益率rlist[0]
rlist=[1:]
elif len(rlist)=0:
利斯特[0]
llist=[1:]
其他:
如果llist[0]

不过,这只是一个框架,你可能会把它做得更好,例如,通过分离循环等。

我知道你希望避免使用“排序”,因为你想要一个更好地描述算法的解决方案,但我真的认为pythonic解决方案需要它

def merge_sorted_lists(left,right):
    return sorted(left+right)
对于公开合理算法而不跟踪索引的非Python解决方案,您可以尝试以下递归解决方案:

def merge_sorted_lists(left,right,acc=[]):
    if not left:
        return acc + right
    if not right:
        return acc + left
    if left[0] < right[0]:
        return merge_sorted_lists(left[1:],right,acc=acc+[left[0]])
    else:
        return merge_sorted_lists(left,right[1:],acc=acc+[right[0]])
def merge_sorted_列表(左、右、acc=[]):
如果没有留下:
返回acc+右侧
如果不正确:
返回acc+左侧
如果左[0]<右[0]:
返回已排序的合并列表(左[1],右,acc=acc+[左[0]])
其他:
返回已排序的合并列表(左、右[1:],acc=acc+[右[0]])

这一个比我的另一个解决方案长了好几行,长输入可能会淹没堆栈。

我意识到这可能是一个写得不太好的方法,但含糊不清的实践含糊不清我要说,强迫用户提供迭代器是不和谐的。因为
it=iter([]);它是iter(it)
,然后您可以对函数内的参数调用
iter
,如果参数不可iterable,则让方法引发异常。我只需执行
left=iter(left)
,这样您还可以将列表或其他可iterable对象传递给函数。这不是非音速的,
iter(generator)
将只返回发电机。在我看来,这段代码基本上还可以,但我想当其中一个生成器为空时,它不能正确处理边缘情况,因为那时它可能仍然会在另一个生成器上迭代。实际上,考虑到约束条件,我不确定这是否是一种特别强烈的代码味道(主要是你不能使用
sort
sorted
,这将是真正的Pythonic操作,下一个最好的方法是使用PyPI中已经实现的mergesort)。我发现手动使用索引比(例如)引入
yield
更可读和更容易理解像这样的“经典算法”练习,可以使用较短的名称,如
i
j
,或
x
y
等,这实际上有助于可读性。
heapq.merge
就是这样做的。(旁注:
\u len=len
可能是出于性能原因,他们不得不做的事情,除非那一点点额外的性能真的很重要)
rlist=[1:][/code>是非法语法,我想你的意思是
rlist=rlist[1:]
相反。但这是一种糟糕的编码实践,因为对于长度
n
的列表,您正在创建
n
平均长度
n/2
的新列表,因此总体上是一种
O(n^2)
算法。可以在
O(n)中合并两个排序的列表
通过使用迭代器,如NightShadeQueen所示。对于像我这样认为“为什么再次排序?那一定非常慢”的人来说,这是一个小小的澄清注释。嗯,(可能)不是,因为它可以利用自然运行。
def merge_sorted_lists(left,right,acc=[]):
    if not left:
        return acc + right
    if not right:
        return acc + left
    if left[0] < right[0]:
        return merge_sorted_lists(left[1:],right,acc=acc+[left[0]])
    else:
        return merge_sorted_lists(left,right[1:],acc=acc+[right[0]])