Python标准库函数用于重新排列列表

7
我想知道Python中是否有标准库函数可以像以下示例那样重新排列列表元素:
a = [1,2,3,4,5,6,7]

function(a)

print a

a = [1,7,2,6,3,5,4]

该算法应该从原始列表的开头获取一个元素,然后从末尾取一个元素,接着再从开头取第二个元素,以此类推。然后重新排列该列表。

敬礼,


6
为什么会有人将这个作为标准库函数呢?你是在寻找用于生成萨丁诗的特定领域语言吗? - hmakholm left over Monica
3
这是一种非常具体的列表重新排序方法。我非常怀疑是否存在标准库函数可以完全实现这个功能。幸运的是,你可以自己编写一个函数来实现。 - Samir Talwar
我非常确定没有标准函数可以做你所要求的事情。你可以使用列表推导式,这将是相当简洁的。 - Lelouch Lamperouge
5
Python是一种编程语言,而不是一个包含各种可想象的程序的大型预构建集合。 - Glenn Maynard
@alwbtc:eknath 意味着 *列表推导式*。 - Aufwind
5个回答

9
你可以使用 itertools 构建一个快速、内存高效的生成器,该生成器可以满足你的需求:
from itertools import chain, izip

def reorder(a):
    gen = chain.from_iterable(izip(a, reversed(a)))
    for _ in a:
        yield next(gen)

>>> list(reorder(a))
<<< [1, 7, 2, 6, 3, 5, 4]

你会发现itertools有很多构建迭代器的强大工具。一个更加简洁的解决方案是:
>>> list(chain.from_iterable(izip(a, reversed(a))))[:len(a)]
<<< [1, 7, 2, 6, 3, 5, 4]

列表推导式是构建列表的另一种非常简洁的方式:

>>> [x for t in zip(a, reversed(a)) for x in t][:len(a)]
<<< [1, 7, 2, 6, 3, 5, 4]

最后,这里有一个有趣的短语:

>>> sum(zip(a, a[::-1]), ())[:len(a)]
<<< (1, 7, 2, 6, 3, 5, 4)

不错!但为什么不用 gen = chain(*izip(a, reversed(a))) 呢? - johnsyweb
1
是的,这样更好,因为“reversed”返回一个迭代器。 - Zach Kelling
是的,但之后我崩溃了 :( - Zach Kelling
最好的人也会遇到这种情况。 :-) - JasonFruit
*izip 不是记忆效率高的,因为它必须立即扩展所有迭代器。您需要 chain.from_iterable(izip(a, reversed(a))) - agf
谢谢!但我已经写了自己的函数,请看:def shake(list): """获取一个列表并重新排序项目, 一个从开头,一个从结尾""" #print "original list is: ", list new_list = []x = len(list) - 1 y = len(list)/2 for i in xrange(y): if list[i] not in new_list: new_list.append(list[i]) if list[i+x] not in new_list: new_list.append(list[i+x]) x -= 2 if len(list)%2 == 1: new_list.append(list[y]) #print "new list is: ", new_list return new_list - alwbtc

3
>>> ((a+a[:0:-1])*len(a))[::len(a)][:len(a)]
[1, 7, 2, 6, 3, 5, 4]

1
惊人的是,但如果len(a)==7,则“(a+a[:0:-1])*len(a)”具有91个元素的长度,如果len(a)==100,则具有19900个元素的长度。 - eyquem
@eyquem,当然这不是高效的,但这个问题引起了我的作业雷达。 - John La Rooy

2
for a in ([1,2,3,4,5,6,7,8,9],
          [1,2,3,4,5,6,7,8],
          [1,2,3,4],
          [1,2,3],
          [1,2,],
          [1],
          []):
    print a
    [ a.insert(i,a.pop()) for i in xrange(1,len(a)+1,2)]
    print a,'\n'

结果

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 9, 2, 8, 3, 7, 4, 6, 5] 

[1, 2, 3, 4, 5, 6, 7, 8]
[1, 8, 2, 7, 3, 6, 4, 5] 

[1, 2, 3, 4]
[1, 4, 2, 3] 

[1, 2, 3]
[1, 3, 2] 

[1, 2]
[1, 2] 

[1]
[1] 

[]
[] 

更新 1

与 zeekay 的代码相比:

from time import clock


n = 100000


te = clock()
for i in xrange(n):
    a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
    [ a.insert(i,a.pop()) for i in xrange(1,len(a)+1,2)]
print clock()-te



from itertools import chain, izip
def reorder(a):
    gen = chain(*izip(a, reversed(a)))
    for _ in a:
        yield next(gen)

te = clock()
for i in xrange(n):
    a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
    a = list(reorder(a)) 
print clock()-te

结果

2.36667984339
5.00051766356

我的方法会直接在原地更改a


2
当然,在Python中只有一种做事情的方式 ;-):
def function(a):
    ret = []
    this_end, other_end = 0, -1
    while a:
        ret.append(a.pop(this_end))
        this_end, other_end = other_end, this_end
    return ret

a = [1,2,3,4,5,6,7]

print function(a)

关于时间:

% python -m timeit 'def function(a):
quote>     ret = []
quote>     this_end, other_end = 0, -1
quote>     while a:
quote>         ret.append(a.pop(this_end))
quote>         this_end, other_end = other_end, this_end
quote>     return ret
quote>
quote> a = [1,2,3,4,5,6,7]
quote>
quote> print function(a)
quote> ' | tail
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
[1, 7, 2, 6, 3, 5, 4]
100000 loops, best of 3: 10.5 usec per loop

1

谢谢大家,我已经编写了自己的函数:

def shake(list):
    """Gets a list and reorders the items,
       one from beginning, one from end"""
    #print "original list is: ", list
    new_list = []

    x = len(list) - 1
    y = len(list)/2

    for i in xrange(y):
        if list[i] not in new_list:
            new_list.append(list[i])
        if list[i+x] not in new_list:
            new_list.append(list[i+x])
        x -= 2

    if len(list)%2 == 1:
        new_list.append(list[y])

    #print "new list is: ", new_list 
    return new_list

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接