复制列表中的字符串,并将整数后缀添加到新添加的后缀中 [英] Duplicate strings in a list and add integer suffixes to newly added ones

查看:110
本文介绍了复制列表中的字符串,并将整数后缀添加到新添加的后缀中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个列表:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆