复制列表中的字符串,并将整数后缀添加到新添加的后缀中 [英] Duplicate strings in a list and add integer suffixes to newly added ones
问题描述
假设我有一个列表:
l = ['a', 'b', 'c']
及其后缀列表:
l2 = ['a_1', 'b_1', 'c_1']
我希望输出为:
out_l = ['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
结果是上面两个列表的交错版本.
The result is the interleaved version of the two lists above.
我可以编写常规的for
循环来完成此操作,但是我想知道是否还有更多的Python方式(例如,使用列表推导或lambda)来完成此操作.
I can write regular for
loop to get this done, but I'm wondering if there's a more Pythonic way (e.g., using list comprehension or lambda) to get it done.
我尝试过这样的事情:
list(map(lambda x: x[1]+'_'+str(x[0]+1), enumerate(a)))
# this only returns ['a_1', 'b_2', 'c_3']
此外,对于一般情况(即2个或更多列表,其中l2
不一定是l
的派生类),需要进行哪些更改?
Furthermore, what changes would need to be made for the general case i.e., for 2 or more lists where l2
is not necessarily a derivative of l
?
推荐答案
yield
您可以使用生成器来解决问题.在每次迭代中,都产生两次 -一次使用原始元素,一次使用带有后缀的元素.
yield
You can use a generator for an elegant solution. At each iteration, yield twice—once with the original element, and once with the element with the added suffix.
发电机将需要耗尽;可以通过在最后添加list
调用来完成.
The generator will need to be exhausted; that can be done by tacking on a list
call at the end.
def transform(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}' # {}_{}'.format(x, i)
您还可以使用yield from
语法进行生成器委派来重新编写此代码:
You can also re-write this using the yield from
syntax for generator delegation:
def transform(l):
for i, x in enumerate(l, 1):
yield from (x, f'{x}_{i}') # (x, {}_{}'.format(x, i))
out_l = list(transform(l))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
如果您使用的是python-3.6之前的版本,请将f'{x}_{i}'
替换为'{}_{}'.format(x, i)
.
If you're on versions older than python-3.6, replace f'{x}_{i}'
with '{}_{}'.format(x, i)
.
概括
考虑一个普通的场景,其中有以下形式的N个列表:
Generalising
Consider a general scenario where you have N lists of the form:
l1 = [v11, v12, ...]
l2 = [v21, v22, ...]
l3 = [v31, v32, ...]
...
您想插入哪一个.这些列表不一定是彼此衍生的.
Which you would like to interleave. These lists are not necessarily derived from each other.
要使用这N个列表处理交织操作,您需要遍历对:
To handle interleaving operations with these N lists, you'll need to iterate over pairs:
def transformN(*args):
for vals in zip(*args):
yield from vals
out_l = transformN(l1, l2, l3, ...)
切片list.__setitem__
从性能角度考虑,我建议这样做.首先为一个空列表分配空间,然后使用切片列表分配将列表项分配到它们的适当位置. l
进入偶数索引,而l'
(已修改l
)进入奇数索引.
Sliced list.__setitem__
I'd recommend this from the perspective of performance. First allocate space for an empty list, and then assign list items to their appropriate positions using sliced list assignment. l
goes into even indexes, and l'
(l
modified) goes into odd indexes.
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)] # [{}_{}'.format(x, i) ...]
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
这一直是我的时间安排中最快的(如下).
This is consistently the fastest from my timings (below).
概括
要处理N个列表,请迭代地分配给切片.
Generalising
To handle N lists, iteratively assign to slices.
list_of_lists = [l1, l2, ...]
out_l = [None] * len(list_of_lists[0]) * len(list_of_lists)
for i, l in enumerate(list_of_lists):
out_l[i::2] = l
zip
+
zip
+ chain.from_iterable
A functional approach, similar to @chrisz' solution. Construct pairs using zip
and then flatten it using itertools.chain
.
from itertools import chain
# [{}_{}'.format(x, i) ...]
out_l = list(chain.from_iterable(zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
iterools.chain
被广泛认为是pythonic列表扁平化方法.
iterools.chain
is widely regarded as the pythonic list flattening approach.
概括
这是最简单的一般化解决方案,我怀疑当N很大时,对于多个列表而言,效率最高.
Generalising
This is the simplest solution to generalise, and I suspect the most efficient for multiple lists when N is large.
list_of_lists = [l1, l2, ...]
out_l = list(chain.from_iterable(zip(*list_of_lists)))
性能
让我们看一下两个列表(一个带有后缀的列表)的简单情况的一些性能测试.一般情况将不会进行测试,因为结果会因数据而异.
Performance
Let's take a look at some perf-tests for the simple case of two lists (one list with its suffix). General cases will not be tested since the results widely vary with by data.
def cs1(l):
def _cs1(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}'
return list(_cs1(l))
def cs2(l):
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]
return out_l
def cs3(l):
return list(chain.from_iterable(
zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
def ajax(l):
return [
i for b in [[a, '{}_{}'.format(a, i)]
for i, a in enumerate(l, start=1)]
for i in b
]
def ajax_cs0(l):
# suggested improvement to ajax solution
return [j for i, a in enumerate(l, 1) for j in [a, '{}_{}'.format(a, i)]]
def chrisz(l):
return [
val
for pair in zip(l, [f'{k}_{j+1}' for j, k in enumerate(l)])
for val in pair
]
这篇关于复制列表中的字符串,并将整数后缀添加到新添加的后缀中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
zip
+ chain.from_iterable
zip
and then flatten it using itertools.chain
.from itertools import chain
# [{}_{}'.format(x, i) ...]
out_l = list(chain.from_iterable(zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
print(out_l)
['a', 'a_1', 'b', 'b_2', 'c', 'c_3']
iterools.chain
被广泛认为是pythonic列表扁平化方法.iterools.chain
is widely regarded as the pythonic list flattening approach.这是最简单的一般化解决方案,我怀疑当N很大时,对于多个列表而言,效率最高.
This is the simplest solution to generalise, and I suspect the most efficient for multiple lists when N is large.
list_of_lists = [l1, l2, ...]
out_l = list(chain.from_iterable(zip(*list_of_lists)))
def cs1(l):
def _cs1(l):
for i, x in enumerate(l, 1):
yield x
yield f'{x}_{i}'
return list(_cs1(l))
def cs2(l):
out_l = [None] * (len(l) * 2)
out_l[::2] = l
out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]
return out_l
def cs3(l):
return list(chain.from_iterable(
zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))
def ajax(l):
return [
i for b in [[a, '{}_{}'.format(a, i)]
for i, a in enumerate(l, start=1)]
for i in b
]
def ajax_cs0(l):
# suggested improvement to ajax solution
return [j for i, a in enumerate(l, 1) for j in [a, '{}_{}'.format(a, i)]]
def chrisz(l):
return [
val
for pair in zip(l, [f'{k}_{j+1}' for j, k in enumerate(l)])
for val in pair
]