我看到如果没有设置条件,列表推导如何擅长返回列表子集甚至是整个板重新映射。但是,过滤条件将返回列表中可能小于过滤列表的值。如何获取返回值的位置并有条件地更改这些元素?
这是一个简单的例子,
>>> v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
>>> t = ['a', 'k']
如何修改v
中t
的元素以映射到新的值,例如'z'
,以产生类似
>>> v = ['z' , 'b' , 'c' , 'd' , 'f' , 'z' , 'g' , 'z', 'd']
有很多关于SO的问题,来自Matlab的人希望做相当于逻辑的索引,但主要是为了选择元素而不是修改他们就像我希望的那样到位。为了修改过滤后的元素,我想做相当于逻辑索引的工作。
我也发现我也无法为Python列表提供多个索引。我使用的是Python 3。
>>> v[ [1,3] ] = 'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list indices must be integers, not list
>>> v[ 1:3 ] = 'z'
>>> v
['a', 'z', 'd', 'f', 'k', 'g', 'a', 'd']
filter
可以为我提供实际对象的迭代,但我无法弄清楚如何修改它们指向的元素。
>>> v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
>>> t = ['a', 'k']
>>> p = filter(lambda x: x in t, v)
>>>
>>> for elem in p :
... print(elem)
...
a
k
a
>>>
>>> for elem in p :
... p = 'z'
...
>>>
>>> for elem in p :
... print(elem)
...
>>>
答案 0 :(得分:2)
您可以使用map
将v
中的值映射到固定值z
(如果它们也在t
中,并保持不变:
>>> print list(map(lambda i: 'z' if i in t else i, v))
['z', 'b', 'c', 'd', 'f', 'z', 'g', 'z', 'd']
或者,你仍然可以使用理解:
>>> v[:] = [i if not (i in t) else 'z' for i in v]
>>> print v
['z', 'b', 'c', 'd', 'f', 'z', 'g', 'z', 'd']
就个人而言,我会发现定义函数更明显,特别是如果你正在处理带有多个参数的函数。因为很容易通过functools.partial
“冻结”固定参数:
>>> def f(value, lookup, mapping_value):
... if value in lookup:
... return mapping_value
... return value
-
>>> from functools import partial
>>> v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
>>> t = ['a', 'k']
>>> func = partial(f, lookup=t, mapping_value='z')
>>> v[:] = [func(i) for i in v]
>>> print v
['z', 'b', 'c', 'd', 'f', 'z', 'g', 'z', 'd']
答案 1 :(得分:1)
如果您尝试更改任何匹配值v in t,最有效的方法是使用make t
a set如果元素是可清除的,只需使用in
:
v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
st = {'a', 'k'}
v[:] = ["z" if s in st else s for s in v]
或者将它与生成器表达式结合使用:
v[:] = ("z" if s in st else s for s in v)
使用v[:]
将修改原始对象/列表v
。
如果您要使用for循环,当您在v中找到一个也在out set中的元素时,您将使用enumerate使用索引更新列表:
v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
st = {'a', 'k'}
for ind,ele in enumerate(v):
if ele in st:
v[ind] = "z"
答案 2 :(得分:1)
Python中MATLAB数组的等价物是一个numpy数组,而不是列表。您不能对列表执行逻辑索引,但您可以在numpy数组上执行。所以对于你的任务,一个numpy数组会运行良好:
>>> import numpy as np
>>>
>>> v = np.array(['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd'])
>>>
>>> v[v == 'a'] = 'z'
>>> v[v == 'k'] = 'z'
>>> print(v)
['z' 'b' 'c' 'd' 'f' 'z' 'g' 'z' 'd']
当你有一个更大的序列时,这会变得复杂。在这种情况下,您可以使用np.in1d
,对于第二个序列中存在的第一个序列的任何元素返回True
,对于任何不存在的任何元素,都返回False
。这也可以用于逻辑索引:
>>> t = ['a', 'c', 'f', 'k']
>>> v[np.in1d(v, t)] = 'z'
>>> print(v)
['z' 'b' 'z' 'd' 'z' 'z' 'g' 'z' 'd']
在这里使用一组(t = {'a', 'c', 'f', 'k'}
)会更快,但我试图让你的例子保持接近。
这种方法大致相当于:
>>> t = ['a', 'c', 'f', 'k']
>>> for ti in t:
... v[v == ti] = 'z'
...
numpy数组也支持多个索引,尽管索引序列本身必须是一个numpy数组。
正如其他人所指出的那样,您可以使用列表推导和成员资格测试进行简单的替换。但是,您也可以使用dict,这可能更简单,并且在我看来更清楚:
>>> t = ['a', 'k']
>>> tdict = dict.fromkeys(t, 'z')
>>> v2 = [tdict.get(vi, vi) for vi in v]
>>> print(v2)
['z', 'b', 'c', 'd', 'f', 'z', 'g', 'z', 'd']
dict.fromkeys
方法创建dict
,其中键是t
的元素,值均为z
。它相当于{ti: 'z' for ti in t}
。
dict.get(x, y)
获取与键y
对应的字典的值,如果没有这样的键,则返回x
。我的代码所做的是它遍历列表中的每个元素。如果该元素位于tdict
中,则会将该值替换为tdict
中的相应值。如果没有,它会将值替换为自身(也就是说,它什么都不做)。
这比成员资格测试示例简单得多。但是,如果您需要使用多个目标和多个替换进行更复杂的替换,那么dict方法将变得很多更清洁:
>>> repdict = {'a': 'z', 'k': 'z', 'i': 'y', 'd': 'y', 'b': 't'}
>>> v2 = [repdict.get(ti, ti) for ti in v]
>>> print(v2)
['z', 't', 'c', 'y', 'f', 'z', 'g', 'z', 'y']
答案 3 :(得分:0)
这应该这样做:
>>> v = ['a' , 'b' , 'c' , 'd' , 'f' , 'k' , 'g' , 'a', 'd']
>>> t = {'a', 'k'}
>>> new_v = [item if (item not in t) else 'z' for item in v]
>>> new_v
['z', 'b', 'c', 'd', 'f', 'z', 'g', 'z', 'd']
>>>