我正在刷新我的python(2.7),我发现了迭代器和生成器。 据我所知,它们是一种有效的方法,可以在不消耗太多内存的情况下导航值。 所以下面的代码在列表上做了某种逻辑索引: 删除触发由函数f。
表示的False条件语句的列表L的值我对我的代码不满意,因为我觉得这段代码不是最佳的,原因有三个:
我在某处读到,使用for循环比使用while循环更好。
但是,在通常的for i in range(10)
中,我无法修改'i'的值,因为迭代似乎并不关心。
逻辑索引在面向矩阵的语言中非常强大,并且应该有一种方法可以在python中做同样的事情(手动授权,但可能比我的代码更好)。
第三个原因就是我想在这个例子中使用generator / iterator来帮助我理解。
第三个原因就是我想在这个例子中使用generator / iterator来帮助我理解。
TL; DR:这段代码是一种很好的pythonic方式来进行逻辑索引吗?
#f string -> bool
def f(s):
return 'c' in s
L=['','a','ab','abc','abcd','abcde','abde'] #example
length=len(L)
i=0
while i < length:
if not f(L[i]): #f is a conditional statement (input string output bool)
del L[i]
length-=1 #cut and push leftwise
else:
i+=1
print 'Updated list is :', L
print length
答案 0 :(得分:3)
此代码存在一些问题,但主要问题是您必须永远不要修改正在迭代的列表。而是从符合条件的元素创建新列表。这可以简单地在for循环中完成:
newlist = []
for item in L:
if f(item):
newlist.append(item)
可以缩短为简单的列表理解:
newlist = [item for item in L if f(item)]
答案 1 :(得分:1)
看起来filter()
就是您所追求的目标:
android/app/build.gradle
filter()
过滤器(...)是一个可迭代的,只保留谓词返回newlist = filter(lambda x: not f(x), L)
的项目。在您的情况下,True
不是谓词,而是f(..)
。
简单:
not f(...)
答案 2 :(得分:0)
“python方式”是使用生成器表达式:
# list comprehension
L = [l for l in L if f(l)]
# alternative generator comprehension
L = (l for l in L if f(l))
如果列表或生成器“更好”,则取决于您的上下文(请参阅例如this so question)。因为您的源数据来自列表,所以在这里使用生成器没有任何实际好处。
答案 3 :(得分:0)
永远不要使用del
,pop
或其他方法修改列表,以便在迭代时改变列表的长度。请阅读this以获取更多信息。
过滤列表的“pythonic”方法是使用重新分配以及列表推导或内置filter
函数:
列表理解:
>>> [item for item in L if f(item)]
['abc', 'abcd', 'abcde']
我想在这个例子中使用generator / iterator来帮助我理解
for item in L
部分 隐式使用迭代器协议。 Python列表是可迭代的,iter(somelist)
返回迭代器。
>>> from collections import Iterable, Iterator
>>> isinstance([], Iterable)
True
>>> isinstance([], Iterator)
False
>>> isinstance(iter([]), Iterator)
True
__iter__
不仅在使用传统的for循环时被调用,而且当你使用列表理解时也是如此:
>>> class mylist(list):
... def __iter__(self):
... print('iter has been called')
... return super(mylist, self).__iter__()
...
>>> m = mylist([1,2,3])
>>> [x for x in m]
iter has been called
[1, 2, 3]
过滤
>>> filter(f, L)
['abc', 'abcd', 'abcde']
在Python3中,使用list(filter(f, L))
获取列表。
当然,要过滤列表,Python也需要迭代它:
>>> filter(None, mylist())
iter has been called
[]
答案 4 :(得分:0)
对于简单删除元素,特别是如果不再需要原始列表,只需向后迭代:
Python 2.x :
for i in xrange(len(L) - 1, -1, -1):
if not f(L[i]):
del L[i]
Python 3.x :
for i in range(len(L) - 1, -1, -1):
if not f(L[i]):
del L[i]
通过从末尾开始迭代,“next”索引在删除后不会改变,并且for
循环是可能的。请注意,您应该使用Python 2中的xrange
生成器或Python 3中的range
生成器来节省内存*。
如果您必须向前迭代,请使用上面给出的解决方案。
*请注意,如果有&gt; = 2 ** 32 - 1个元素,Python 2的xrange
将会中断。 Python 3的range
以及效率较低的Python 2 range
没有这个限制。