你如何概括创建一个包含许多变量和条件`if`的列表?

Tom*_*ski 17 python if-statement list

我创建一个列表如下:

['v0' if x%4==0 else 'v1' if x%4==1 else 'v2' if x%4==2 else 'v3' for x in list_1]
Run Code Online (Sandbox Code Playgroud)

如何推广这样一个列表的创建,以便它可以通过更多的变量和后续条件轻松扩展?

Wil*_*sem 32

字符串格式

为什么不在这里使用模运算,并进行字符串格式化,如:

['v{}'.format(x%4) for x in list_1]
Run Code Online (Sandbox Code Playgroud)

在这里,我们计算x%4,并将其附加到'v字符串中.好消息是我们可以很容易地改变4到另一个数字.

元组或列表索引

如果输出字符串不遵循这样的结构,我们可以构造一个列表或元组来保存这些值.喜欢:

# in case the values do not follow a certain structure
vals = ('v0', 'v1', 'v2', 'v3')
[vals[x%4] for x in list_1]
Run Code Online (Sandbox Code Playgroud)

通过这种方式对其进行索引,很清楚哪些值将映射到哪个索引.这工作不错,考虑到操作的结果-在这里x%4-映射到一个ñ(有合理的小ñ).

(默认)词典

如果操作不映射在ñ,但仍然在有限数量的哈希的项目,我们可以使用字典.例如:

d = {0: 'v0', 1: 'v1', 2: 'v2', 3: 'v3'}
Run Code Online (Sandbox Code Playgroud)

或者如果我们想要一个"回退"值,给定查找失败时使用的值:

from collections import defaultdict

d = defaultdict(lambda: 1234, {0: 'v0', 1: 'v1', 2: 'v2', 3: 'v3'})
Run Code Online (Sandbox Code Playgroud)

这里1234用作后备值,然后我们可以使用:

[d[x%4] for x in list_1]
Run Code Online (Sandbox Code Playgroud)

如果我们想要防止那些失败的查找被忽视,那么使用d[x%4]over d.get(x%4)给出d的字典会更有用.在那种情况下会出错.虽然错误通常不是一个好兆头,但是在查找失败的情况下引发错误比添加默认值更好,因为它可能是某些东西无法正常工作的症状.

  • 这个答案特定于模运算.当OP有一些任意操作和任意值返回时,一般情况怎么样? (3认同)

cs9*_*s95 20

以下是我对通用解决方案的尝试.一,设置 -

list_1 = [1, 2, 4, 5, 10, 4, 3]
Run Code Online (Sandbox Code Playgroud)

前两个选项是基于纯python的,而后两个选项使用数字库(numpy和pandas).


dict.get

生成mapping值的键.在列表理解中,查询dict.get-

mapping = {0 : 'v0', 1 : 'v1', 2 : 'v2'}
r = [mapping.get(x % 4, 'v3') for x in list_1]
Run Code Online (Sandbox Code Playgroud)

r
['v1', 'v2', 'v0', 'v1', 'v2', 'v0', 'v3']
Run Code Online (Sandbox Code Playgroud)

这里'v3'是当结果x % 4不存在作为键时返回的默认值mapping.

这适用于任何一组任意条件和值,而不仅仅是问题中概述的条件(模运算).


collections.defaultdict

使用defaultdict- 可以使用类似的解决方案-

from collections import defaultdict

mapping = defaultdict(lambda: 'v3', {0: 'v0', 1: 'v1', 2: 'v2', 3: 'v3'})
r = [mapping[x % 4] for x in list_1]
Run Code Online (Sandbox Code Playgroud)

r
['v1', 'v2', 'v0', 'v1', 'v2', 'v0', 'v3']
Run Code Online (Sandbox Code Playgroud)

这与选项1类似.


numpy.char.add

如果您使用numpy,那么您可能对涉及模运算和广播添加的矢量化解决方案感兴趣 -

r = np.char.add('v', (np.array(list_1) % 4).astype('<U8'))
Run Code Online (Sandbox Code Playgroud)

r
array(['v1', 'v2', 'v0', 'v1', 'v2', 'v0', 'v3'],
      dtype='<U9')
Run Code Online (Sandbox Code Playgroud)

如果您需要列表作为最终结果,则可以致电r.tolist().请注意,此解决方案针对您的特定用例进行了优化.numpy使用np.where/ 可以实现更通用的方法np.select.


pd.Series.mod+ pd.Series.radd

类似的解决方案也适用于pandas mod+ radd-

r = pd.Series(list_1).mod(4).astype(str).radd('v')
r

0    v1
1    v2
2    v0
3    v1
4    v2
5    v0
6    v3
dtype: object
Run Code Online (Sandbox Code Playgroud)

r.tolist()
['v1', 'v2', 'v0', 'v1', 'v2', 'v0', 'v3']
Run Code Online (Sandbox Code Playgroud)

  • @WillemVanOnsem谢谢.我的答案旨在解决适用于任何条件和价值观的一般情况.我想我不清楚这一点,并且downvoter没有接受它. (2认同)
  • Nitpick:基于dict的方法将为列表中的每个匹配项分配相同的实例,而OP的原始代码每次都会创建一个新实例.很可能这根本不是问题(当然不是字符串或数字),但在某些情况下可能是.只是想指出这一点. (2认同)