我有两个列表如下
f = ['sum_','count_','per_']
d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
所以我想在列表d的所有项目中应用f中每个字符串的lstrip,以便我可以得到
d = ['fav_genre','fav_event','fav_type','fav_movie']
我想用列表理解来做。 但我知道我也可以用其他方式来做,比如使用re.sub,每次在d列表项上应用replace
#example
d = [re.sub(r'.*fav', 'fav', x) for x in d] #####gives what i want
## but if fav (which in this case a matching pattern) is not there in d then this solution won't work
## d = ['fav_genre','sum_any_event','count_some_type','per_all_movie']
#re.sub can't be applied on this d(as before) as no matching char like 'fav' found
所以列表压缩是我选择做的..
到目前为止,我已经尝试过..d_one = [x.lstrip('count_') for x in d] ###only count_ is stripped
# o/p- d-one = ['fav_genre', 'sum_fav_event', 'fav_type', 'per_fav_movie']
# so i c_n apply lstrip of each string from f on items of d
## why not apply all items lstrip in one go ### so tried
d_new = [x.lstrip(y) for y in f for x in d]
###['fav_genre', 'fav_event', 'count_fav_type', 'per_fav_movie', 'fav_genre', 'sum_fav_event', 'fav_type', 'per_fav_movie', 'fav_genre', 'sum_fav_event', 'count_fav_type', 'fav_movie']
所以它给了我lstrip应用的每次迭代的结果
请建议我如何在列表理解中逐步应用所有lstrip(递归)。在此先感谢。
答案 0 :(得分:3)
试试这个:
>>> f = ['sum_','count_','per_']
>>> d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
>>> [s[len(([p for p in f if s.startswith(p)]+[""])[0]):] for s in d]
['fav_genre', 'fav_event', 'fav_type', 'fav_movie']
我相信这可以按预期处理所有情况。
答案 1 :(得分:3)
可以使用以下方法,根据f
:
import re
f = ['sum_','count_','per_']
d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
re_prefix = re.compile(r'^({})'.format('|'.join(f)))
print [re_prefix.sub('', entry) for entry in d]
或者作为一个单行(不那么有效):
print [re.sub(r'^({})'.format('|'.join(f)), '', entry) for entry in d]
给你以下输出:
['fav_genre', 'fav_event', 'fav_type', 'fav_movie']
答案 2 :(得分:1)
这就是你要找的东西?
>>> f = ['sum_','count_','per_']
>>> d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
>>> [x[len(y):] for x in d for y in f if x.startswith(y)]
['fav_event', 'fav_type', 'fav_movie']
编辑: 我越是嘲笑这一点,我就越发现列表理解不可能。问题似乎包括不匹配的条件,但是一个简单的“其他”条件。当迭代f中的其他项目时,会导致d中的每个项目被包括在内。
例如
>>> [x[len(y):] if x.startswith(y) else x for x in d for y in f
['fav_genre', 'fav_genre', 'fav_genre', 'fav_event', 'sum_fav_event', 'sum_fav_event', 'count_fav_type', 'fav_type', 'count_fav_type', 'per_fav_movie', 'per_fav_movie', 'fav_movie']
这会创建一个包含太多项目的新列表。
向列表comp添加另一个条件会生成语法错误:
[x[len(y):] if x.startswith(y) else x if x[len(y):] not in f for x in d for y in f]
File "<stdin>", line 1
[x[len(y):] if x.startswith(y) else x if x[len(y):] not in f for x in d for y in f]
^
SyntaxError: invalid syntax
即使我们能够通过列表理解来实现这一点,函数也会更具可读性:
def strip_prefixes(prefixes, mylist):
for element in mylist:
for x in prefixes:
if element.startswith(x):
element = element[len(x):]
return mylist
答案 3 :(得分:1)
不要太多地使用列表理解来做这件事。列表理解,如果非常像map / reduce语法糖。通过使用简单的函数,您将获得更容易阅读的解决方案。
import re
f = ['sum_','count_','per_']
d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
def makeTrimmer(patterns):
regex = re.compile("^(%s)" % "|".join(patterns))
def trimmer(string):
old_string = string
new_string = re.sub(regex, "", old_string)
while len(old_string) != len(new_string):
old_string = new_string
new_string = re.sub(regex, "", old_string)
return new_string
return trimmer
trimmer = makeTrimmer(f)
vals = [trimmer(x) for x in d]
print vals
正如您所看到的,trimmer
函数非常易读,您可以在列表解析中执行此操作,但没有简单的方法可以做到这一点。因为列表推导的if部分非常类似于要输出的事物列表上的过滤器。 for部分是组合条目,第一部分是构建条目输出。在您的情况下,您只需要根据多个前缀构建正确的输出...换句话说,您不是要尝试将所有前缀与所有值组合成多个输出,而您不会过滤任何结果。
我的方法可能可以通过lambdas实现,但这很可能是丑陋的。
没有lambda的非递归方法:
vals = [
re.sub(re.compile("^(%s)" % "|".join(f)), "", x)
for x in d
]
print vals
这是使用匿名lambdas的完整递归:
# -*- coding: utf-8 -*-
import re
f = ['sum_','count_','per_']
d = ['fav_genre','sum_fav_event','count_fav_type','per_fav_movie']
vals = [
(lambda a, *b: a(a, *b))(
(lambda loop, newstring, oldstring:
newstring
if len(newstring) == len(oldstring) else
loop(
loop,
newstring,
re.sub(re.compile("^(%s)" % "|".join(f)), "", x)
)
),
re.sub(re.compile("^(%s)" % "|".join(f)), "", x),
x
)
for x in d
]
print vals
这与上述方法基本相同,只是我们使用递归方法调用进一步过滤,因此此方法将sum_count_per_fun_avg
之类的内容清除为fun_avg
。
另外,不要使用lambda方法,效率低下。
但这是一个更高效的lambda版本:
vals = [
(lambda regex:
(lambda a, *b: a(a, *b))(
(lambda loop, newstring, oldstring:
newstring
if len(newstring) == len(oldstring) else
loop(
loop,
newstring,
re.sub(regex, "", x)
)
),
re.sub(regex, "", x),
x
)
)(re.compile("^(%s)" % "|".join(f)))
for x in d
]
我们只编译一次正则表达式。但是python中的递归仍然是一个问题所以你不应该使用递归。
答案 4 :(得分:1)
我准备去睡觉,但正在努力。我认为这样做可能不是最好的主意,因为它是很多循环并且不那么可读。这也不太对。
d_new = set([(x,y) for x in [x.split(y)[1] for y in f for x in d if x.startswith(y)] for y in [x for x in d if x.startswith('fav')]])
它目前将它们放入元组中,您可以在集合中为x添加另一个x来提取不同的元组对。在这一点上虽然我甚至认为使用列表理解它是有用的或值得的,但如果你真的想使用它,这可能会给你一个开始。
修改强>
代码看起来像这样:
[('fav_movie','fav_genre'),('fav_event','fav_genre'),('fav_type', 'fav_genre')]