无法在Python中插入(无与空列表)

时间:2013-11-12 19:53:08

标签: python insert nonetype

我正在尝试从Google的Python类中解决以下练习。

电子。给定按递增顺序排序的两个列表,创建并返回按排序顺序排列的所有元素的合并列表。您可以修改传入的列表。理想情况下,解决方案应该在“线性”时间内工作,只需对两个列表进行一次传递。

我正在使用以下方案方法(我希望我有车,cdr和缺点!)。

def helper(list1, list2, result):
  if list1 == None:
    return result + list2
  elif list2 == None:
    return result + list1
  elif list1[0] < list2[0]:
    return helper(list1[1:], list2, result.insert(0, list1[0]))
  else:
    return helper(list1, list2[1:], result.insert(0, list2[0]))

def linear_merge(list1, list2):
  helper(list1, list2, [])

我得到的错误是,当结果为[]时,我似乎无法在结果中插入元素:

AttributeError: 'NoneType' object has no attribute 'insert'

但这在控制台中运行良好:

>>> b = []
[]
>>> b.insert(0, 4)
>>> b
[4]

我是Python的新手,所以我有两个问题:

  1. 我对缺少与[]的看法,以及如何让这段代码生效?
  2. 如果Python不适用于Scheme / Lisp方法,那么解决这个问题的“Python方式”是什么?这对我来说不那么重要,因为我可以查看解决方案。
  3. 谢谢!

4 个答案:

答案 0 :(得分:5)

list.insert返回None,而不是修改后的列表。

这需要将helper更改为读取

def helper(list1, list2, result):
  if not list1:
    return result + list2
  elif not list2:
    return result + list1
  elif list1[0] < list2[0]:
    return helper(list1[1:], list2, result + [list1[0]])
  else:
    return helper(list1, list2[1:], result + [list2[0]])

请注意两个基本案例的更改。 None和空列表[]不是一回事。测试列表是否为空的pythonic方法是将列表视为布尔值:空列表为False,其他列表为True


正如其他人在我之前注意到的那样,您需要在helper中明确返回linear_merge的返回值。

答案 1 :(得分:3)

第一个问题是[]None不相等。

这会导致两个问题。


首先,您对递归基本案例的测试无效。如果您尝试测试列表为空,可以通过多种方式进行测试:

if not list1:

if list1 == []:

if len(list1) == 0:

但将其与None进行比较不是其中之一。

第一种通常被认为是最具Pythonic的(并且由PEP 8风格指南明确鼓励)。


其次,你显然是用None显式调用这个函数作为参数,你在代码中没有向我们展示过。不要那样做。如果您的意思是[],请拨打[]


另一个问题是像list.insert这样的可变方法不返回变异对象,它们返回None。所以,而不是:

return helper(list1[1:], list2, result.insert(0, list1[0]))

......你需要这样做:

result.insert(0, list1[0])
return helper(list1[1:], list2, result)

...或者改为使用非变异表达式:

return helper(list1[1:], list2, [list1[0]] + result)

然后,您的linear_merge没有return任何内容,因此其值为None。将其更改为:

return helper(list1, list2, [])

答案 2 :(得分:1)

result.insert未返回新列表;它会修改现有的result。因此,最后将None作为嵌套helper()调用的第三个参数传递,因为这是result.insert返回的内容 - None


另请注意:

def linear_merge(list1, list2):
    helper(list1, list2, [])

由于您return没有linear_merge任何内容,因此您总是会得到None

答案 3 :(得分:0)

既然你要求Pythonic解决方案,以及如何解决你的尝试,我会把你写成一个单独的答案。

我通过使用迭代器来做到这一点。在每一步,您产生较低的值并拉动下一个值。就像你在Haskell中一样。*这实际上线性时间,而且它也是懒惰的。使用more-itertools

def itermerge(i1, i2):
    i1, i2 = iter(i1), more_itertools.peekable(iter(i2))
    for v1 in i1:
        while i2 and i2.peek() < v1:
            yield next(i2)
        yield v1
    yield from i2

如果您需要Python 2.x或3.2兼容性,只需使用yield from i2更改for v2 in i2: yield v2


如果不清楚这是如何工作的,这里是最明确的版本,以准确显示每一步发生的事情:

def itermerge(i1, i2):
    i1, i2 = iter(i1), iter(i2)
    sentinel = object()
    v1, v2 = sentinel, sentinel
    while True:
        if v1 is sentinel:
            try:
                v1 = next(i1)
            except StopIteration:
                yield from i2
                return
        if v2 is sentinel:
            try:
                v2 = next(i2)
            except StopIteration:
                yield from i1
                return
        if v1 < v2:
            yield v1
            v1 = sentinel
        else:
            yield v2
            v2 = sentinel

如果您需要一个返回列表的函数,那很简单:

def linear_merge(l1, l2):
    return list(itermerge(l1, l2))

*这有点儿开玩笑。虽然你可以在Haskell中编写这个算法的几乎任何不可变版本,但最喜欢这个解决方案的那个可能不是你写的那个。