Python相当于maplist?

时间:2009-05-27 17:13:40

标签: python functional-programming lisp

Common Lisp maplist函数的最佳Python等价物是什么?来自maplist documentation

  

maplist就像mapcar一样   函数应用于连续   列表的子列表。功能是   首先应用于列表本身,   然后到每个列表的cdr,和   然后到每个cdr的cdr   列表,等等。

示例(伪代码,未测试):

>>> def p(x): return x
>>> maplist(p, [1,2,3])
[[1, 2, 3], [2, 3], [3]]

注意:在上面示例中传递给p的参数将是列表[1, 2, 3][2, 3][3];即,p未应用于这些列表的元素。 E.g:

>>> maplist(lambda l: list(reversed(l)), [1,2,3])
[[3, 2, 1], [3, 2], [3]]

9 个答案:

答案 0 :(得分:11)

你可以为那个

写一个小功能
def maplist(func, values):
    return [map(func, values[i:]) for i in xrange(len(values))]

>>> maplist(lambda a: a* 2, [1,2,3])
[[2, 4, 6], [4, 6], [6]]

<强> [编辑]

如果要在子列表上应用该功能,可以将功能更改为:

def maplist(func, values):
    return [func(values[i:]) for i in xrange(len(values))]

>>> maplist(lambda l: list(reversed(l)), [1,2,3])
[[3, 2, 1], [3, 2], [3]]

答案 1 :(得分:6)

正如@Cybis和其他人所提到的,你无法保持Python列表的O(N)复杂性;你必须创建一个链表。冒着证明Greenspun's 10th rule的风险,这是一个解决方案:

class cons(tuple):
    __slots__=()

    def __new__(cls, car, cdr):
        return tuple.__new__(cls, (car,cdr))

    @classmethod
    def from_seq(class_, l):
        result = None
        for el in reversed(l):
            result = cons(el, result)
        return result

    @property
    def car(self): return self._getitem(0)

    @property
    def cdr(self): return self._getitem(1)

    def _getitem(self, i):
        return tuple.__getitem__(self, i)

    def __repr__(self):
        return '(%s %r)' % (self.car, self.cdr)

    def __iter__(self):
        v = self
        while v is not None:
            yield v.car
            v = v.cdr

    def __len__(self):
        return sum(1 for x in self)

    def __getitem__(self, i):
        v = self
        while i > 0:
            v = v.cdr
            i -= 1
        return v.car

def maplist(func, values):
    result = [ ]
    while values is not None:
        result.append(func(values))
        values = values.cdr
    return result

测试产量:

>>> l = cons.from_seq([1,2,3,4])
>>> print l
(1 (2 (3 (4 None))))
>>> print list(l)
[1, 2, 3, 4]
>>> print maplistr(lambda l: list(reversed(l)), cons.from_seq([1,2,3]))
[[3, 2, 1], [3, 2], [3]]

编辑:这是一个基于生成器的解决方案,基本上解决了相同的问题,而不使用链接列表:

import itertools

def mapiter(func, iter_):
    while True:
        iter_, iter2 = itertools.tee(iter_)
        iter_.next()
        yield func(iter2)

测试产量:

>>> print list(mapiter(lambda l: list(reversed(list(l))), [1,2,3]))
[[3, 2, 1], [3, 2], [3]]

答案 2 :(得分:3)

Eewww ...切片列表是线性时间操作。到目前为止发布的所有解决方案都具有O(n ^ 2)时间复杂度。我相信,Lisp的地图列表有O(n)。

问题是,Python的列表类型不是链表。它是一个动态可调整大小的数组(即,类似于C ++ STL的“向量”类型)。

如果保持线性时间复杂度对您很重要,则无法在Python列表上创建“maplist”函数。最好修改你的代码以使用索引到列表中,或者将列表转换为实际的链表(仍然是线性时间操作,但会有很多开销)。

答案 3 :(得分:1)

这就像你的例子(我修改了reyjavikvi的代码)

def maplist(func, l):
    result=[]
    for i in range(len(l)):
        result.append(func(l[i:]))
    return result

答案 4 :(得分:1)

您可以使用嵌套列表推导:

>>> def p(x): return x
>>> l = range(4)[1:]
>>> [p([i:]) for i in range(len(l))]
[[1, 2, 3], [2, 3], [3]]

您可以自己定义地图列表:

>>> def maplist(p, l): return [p([i:]) for i in range(len(l))]
>>> maplist(p, l)
[[1, 2, 3], [2, 3], [3]]

答案 5 :(得分:1)

O(N)实现链接列表的maplist()

maplist = lambda f, lst: cons(f(lst), maplist(f, cdr(lst))) if lst else lst

请参阅Python Linked List问题。

答案 6 :(得分:1)

Python有一个链表类型,名为deque

from collections import deque

def maplist(f, lst):
    linked = deque(lst)
    results = []
    while linked:
        results.append(f(linked))
        linked.popleft() # assumes left is head, as in lisp

    return results

In [134]: maplist(lambda l: list(reversed(l))*2, [1,2,3])
Out[134]: [[3, 2, 1, 3, 2, 1], [3, 2, 3, 2], [3, 3]]

线性时间,同样的事情,将具有与lisp列表上的操作相同的性能特征(即修改内部元素将在被修改的列表的长度中是线性的),以及相同的语义(即,如果{{1修改列表,它会在f调用中为f的所有后续执行修改它;但是,因为这会创建maplist的副本,lst无法修改{ {1}},与Common Lisp不同。

答案 7 :(得分:0)

修改亚伦的答案:

In [8]: def maplist(p, l): return [p([x for x in l[i:]]) for i in range(len(l))]
   ...: 

In [9]: maplist(lambda x: x + x, [1,2,3])
Out[9]: [[1, 2, 3, 1, 2, 3], [2, 3, 2, 3], [3, 3]]

答案 8 :(得分:-1)

我认为没有,但以下功能可以起作用:

def maplist(func, l):
    for i in range(len(l)):
        func(l[i:])