我希望创建一个列表,其值根据一组已知模式进行交替。请注意,每个前缀可能没有相同数量的项目。 (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个不同的服务器发出请求时,希望将其用作一种限制机制。
答案 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)
这将返回单词中的列表词典错误,并在单词中返回前缀。