使用交替值创建列表

时间:2016-10-21 18:43:45

标签: python

我希望创建一个列表,其值根据一组已知模式进行交替。请注意,每个前缀可能没有相同数量的项目。 (2个foos,3个bar,3个spams)。我目前的解决方案是令人讨厌的gaggle,即.pop()'来自使用公共前缀构建的列表并附加到新列表。

prefix_patterns = ['foo','bar','spam']

inlist = ['fooABC','fooXYZ','barABC','barXYZ','spamABC','bar123','spamXYZ','spam123']

期望的输出:

outlist = ['fooABC','barABC','spamABC','fooXYZ','barXYZ','spamXYZ','bar123','spam123']

当前解决方案(不处理不同长度的列表):

foos = [value for value in inlist if 'foo' in value]
bars = [value for value in inlist if 'bar' in value]
spams = [value for value in inlist if 'spam' in value]

while foos:
    outlist.append(foos.pop())
    outlist.append(bars.pop())
    outlist.append(spams.pop())

对于上下文:在向4个不同的服务器发出请求时,希望将其用作一种限制机制。

4 个答案:

答案 0 :(得分:1)

inlist =['fooABC','fooXYZ','barABC','barXYZ','spamABC','bar123','spamXYZ','spam123']

new_inlist = []

separator = '-'

# Adding separator, I believe it won't require in real scenario as there must be separator between host and user.
for prefix in ['foo', 'bar', 'spam']:
    for item in inlist:
        if item.startswith(prefix):
           new_inlist.append(item.replace(prefix, prefix + separator))

# Ultimately new_inlist ->
#['foo-ABC','foo-XYZ','bar-ABC','bar-XYZ','spam-ABC','bar-123','spam-XYZ','spam-123']

# Now Just do sorting
new_inlist.sort(key=lambda x: x.split(separator)[1])

答案 1 :(得分:1)

由于您使用的是 Python 2.x ,因此可以使用:

# group by prefix first -> [['fooXX']['barXX']['spamXX']]
prefix_match = [[x for x in inlist if x.startswith(pre)] for pre in prefix_patterns]
outlist = [x for i in map(None,*prefix_match) for x in i if x]

如果其中一个列表太短,则map内置函数会将prefix_match压缩在一起并填充None。然后,您可以简单地展平此列表并排除任何None个对象。

对于 Python 3.x ,您可以使用itertools.zip_longest替换地图功能:

from itertools import zip_longest
prefix_match = [[x for x in inlist if x.startswith(pre)] for pre in prefix_patterns]
outlist = [x for i in zip_longest(*prefix_match) for x in i if x]

答案 2 :(得分:0)

您正在寻找itertools食谱roundrobin。

from itertools import cycle, islice

prefix_patterns = ['foo','bar','spam']
inlist = ['fooABC','fooXYZ','barABC','barXYZ','spamABC','bar123','spamXYZ','spam123']
outlist = ['fooABC','barABC','spamABC','fooXYZ','barXYZ','spamXYZ','bar123','spam123']

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))

def check_prefix(item):
    for prefix in prefix_patterns:
        if item.startswith(prefix):
            return prefix

group = {}
for item in inlist:
    key = check_prefix(item)
    group.setdefault(key, []).append(item)
print([x for x in roundrobin(*list(group.values()))])

>> ['barABC', 'spamABC', 'fooABC', 'barXYZ', 'spamXYZ', 'fooXYZ', 'bar123', 'spam123']

答案 3 :(得分:0)

我玩排序:

def prefix_sort(string):
    for prefix in ('foo','bar','spam'):
       if prefix == string[:len(prefix)]: break
    return (string[len(prefix):],prefix)

sorted(inlist,key=prefix_sort)

这将返回单词中的列表词典错误,并在单词中返回前缀。