我有一个字符串,其中的单词用空格分隔(所有单词都是唯一的,没有重复)。我将此字符串转换为列表:
s = "#one cat #two dogs #three birds"
out = s.split()
计算创建的值的数量:
print len(out) # Says 192
然后我尝试删除列表中的所有内容:
for x in out:
out.remove(x)
然后重新计算:
print len(out) # Says 96
有人可以解释为什么它说96而不是0?
更多信息
每一行都以'#'开头,实际上是一对以空格分隔的单词对:第一对是键,第二个是值。
所以,我正在做的是:
for x in out:
if '#' in x:
ind = out.index(x) # Get current index
nextValue = out[ind+1] # Get next value
myDictionary[x] = nextValue
out.remove(nextValue)
out.remove(x)
问题是我无法将所有键值对移动到字典中,因为我只迭代了96个项目。
答案 0 :(得分:13)
至于 for 循环中实际发生的事情:
来自 Python for statement documentation:
表达式列表的评估一次;它应该产生一个可迭代的 宾语。为
expression_list
的结果创建了一个迭代器。 然后,对于由提供的每个项目,一次执行该套件 迭代器,按升序索引。每个项目依次是 使用分配的标准规则分配给目标列表, 然后套件被执行。 当项目耗尽时(即 当序列为空时立即,else
子句中的套件, 如果存在,则执行,loop
终止。
我认为最好借助插图来展示。
现在,假设您有iterable object
(例如list
),请执行以下操作:
out = [a, b, c, d, e, f]
for x in out
执行的操作是创建内部索引器,就像这样(我用符号^
来说明):
[a, b, c, d, e, f]
^ <-- here is the indexer
通常情况是:当您完成循环的一个循环时,索引器向前移动,如下所示:
[a, b, c, d, e, f] #cycle 1
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 2
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 3
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 4
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 5
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 6
^ <-- here is the indexer
#finish, no element is found anymore!
正如您所看到的,索引器一直向前发展直到您的结束 列表,无论列表中发生了什么!
因此,当您执行remove
时,这就是内部发生的事情:
[a, b, c, d, e, f] #cycle 1
^ <-- here is the indexer
[b, c, d, e, f] #cycle 1 - a is removed!
^ <-- here is the indexer
[b, c, d, e, f] #cycle 2
^ <-- here is the indexer
[c, d, e, f] #cycle 2 - c is removed
^ <-- here is the indexer
[c, d, e, f] #cycle 3
^ <-- here is the indexer
[c, d, f] #cycle 3 - e is removed
^ <-- here is the indexer
#the for loop ends
请注意,只有 3个周期而不是 6个周期(!!)(这是原始列表中元素的数量)。这就是你离开原始len
的一半 len
的原因,因为这是你删除一个元素时完成循环所需的周期数从每个周期开始。
如果要清除列表,只需执行以下操作:
if (out != []):
out.clear()
或者,或者,要逐个删除元素,您需要反过来 - 从结尾到开头。使用reversed
:
for x in reversed(out):
out.remove(x)
现在,为什么reversed
会起作用?如果索引器继续向前移动,那么reversed
也不应该工作,因为每个周期元素的数量减少了一个吗?
不,不是那样,
因为
reversed
方法更改了到内部索引器的方式 作品!使用reversed
方法时发生的事情是来制作 内部索引器向后移动(从结尾)而不是 转发强>
为了说明这是正常情况:
[a, b, c, d, e, f] #cycle 1
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 2
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 3
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 4
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 5
^ <-- here is the indexer
[a, b, c, d, e, f] #cycle 6
^ <-- here is the indexer
#finish, no element is found anymore!
因此,当您每个周期执行一次删除时,它不会影响索引器的工作方式:
[a, b, c, d, e, f] #cycle 1
^ <-- here is the indexer
[a, b, c, d, e] #cycle 1 - f is removed
^ <-- here is the indexer
[a, b, c, d, e] #cycle 2
^ <-- here is the indexer
[a, b, c, d] #cycle 2 - e is removed
^ <-- here is the indexer
[a, b, c, d] #cycle 3
^ <-- here is the indexer
[a, b, c] #cycle 3 - d is removed
^ <-- here is the indexer
[a, b, c] #cycle 4
^ <-- here is the indexer
[a, b] #cycle 4 - c is removed
^ <-- here is the indexer
[a, b] #cycle 5
^ <-- here is the indexer
[a] #cycle 5 - b is removed
^ <-- here is the indexer
[a] #cycle 6
^ <-- here is the indexer
[] #cycle 6 - a is removed
^ <-- here is the indexer
希望插图可以帮助您了解内部发生的事情......
答案 1 :(得分:8)
我认为你真的想要这样的东西:
s = '#one cat #two dogs #three birds'
out = s.split()
entries = dict([(x, y) for x, y in zip(out[::2], out[1::2])])
这段代码在做什么?让我们分解吧。首先,我们将s
按空格分成out
。
接下来,我们遍历out
中的对,称其为“x, y
”。这些对成为元组/对的list
。 dict()
接受包含两个元组大小的列表,并将其视为key, val
。
这是我尝试时得到的结果:
$ cat tryme.py
s = '#one cat #two dogs #three birds'
out = s.split()
entries = dict([(x, y) for x, y in zip(out[::2], out[1::2])])
from pprint import pprint
pprint(entries)
$ python tryme.py
{'#one': 'cat', '#three': 'birds', '#two': 'dogs'}
答案 2 :(得分:3)
你并不具体。你为什么要删除列表中的所有内容?如果您需要做的就是清除列表清单,为什么不这样做呢:
out = []
答案 3 :(得分:2)
您遇到的问题是在迭代时修改列表的结果。删除项目后,其后的所有内容都会向前移动一个索引,但迭代器不会考虑更改并继续增加上次访问的索引。因此迭代器会跳过列表中的每一个元素,这就是为什么你剩下一半元素的原因。
对您的问题最简单的直接解决方案是使用切片表示法迭代out
的副本:
for x in out[:]:
# ...
out.remove(x)
但是,这里有一个更深层次的问题:为什么你需要从列表中删除项目?使用您的算法,您可以保证最终得到一个空列表,这对您没用。在不删除项目的情况下迭代列表会更简单,更有效。
当您完成列表(在for循环块之后)时,您可以显式删除它(使用del
关键字)或者只是将其留给Python的垃圾收集系统来处理。
还有一个问题:您将列表上的直接迭代与基于索引的引用相结合。 for x in out
的使用通常应限于您希望独立于其他元素访问每个元素的情况。如果您要使用索引,请使用for i in range(len(out))
并使用out[i]
访问元素。
此外,您可以使用词典理解以单行pythonic表达式完成整个任务:
my_dictionary = {out[i]: out[i + 1] for i in range(len(out)) if "#" in out[i]}
另一个pythonic替代方案是利用每个偶数元素是一个键的事实,每个奇数元素都是一个值(你必须假设str.split()
的列表结果始终遵循此模式),并在偶数和奇数子列表上使用zip
。
my_dictionary = dict(zip(out[::2], out[1::2]))
答案 4 :(得分:2)
我相信你想跟随。
>>> a = '#one cat #two dogs #three birds'
>>> b = { x.strip().split(' ')[0] : x.strip().split(' ')[-1] for x in a.strip().split('#') if len(x) > 0 }
>>> b
{'three': 'birds', 'two': 'dogs', 'one': 'cat'}
甚至更好
>>> b = [ y for x in a.strip().split('#') for y in x.strip().split(' ') if len(x) > 0 ]
>>> c = { x: y for x,y in zip(b[0::2],b[1::2]) }
>>> c
{'three': 'birds', 'two': 'dogs', 'one': 'cat'}
>>>
答案 5 :(得分:1)
如果您只需要清除列表,
使用
out = []
要么
out.clear()
无论如何,你说的是因为列表的remove
功能会影响列表。
out = ['a', 'b', 'c', 'd', 'e', 'f']
for x in out:
out.remove(x)
print(x)
然后结果显示如下:
一 C ë
这正是完整列表的一半。所以,在你的情况下,你从192获得96(一半的192)。
答案 6 :(得分:1)
问题在于,无论何时从列表中删除值,该特定列表都会动态恢复其值。
也就是说,当您执行out.remove(ind)
和out.remove(ind+1)
时,会删除这些索引中的值,
但它们被替换为前一个值的前身的新值。
因此,为避免这种情况,您必须按如下方式实现代码:
out = []
out = '#one cat #two dogs #three birds'.split()
print "The list is : {0} \n".format(out)
myDictionary = dict()
for x in out:
if '#' in x:
ind = out.index(x) # Get current index
nextValue = out[ind+1] # Get next value
myDictionary[x] = nextValue
out = [] # #emptying the list
print("The dictionary is : {0} \n".format(myDictionary))
因此,在您将值从列表传输到字典后,我们可以安全地清空out
使用out = []
答案 7 :(得分:0)
问题是你在迭代时使用remove(x)。 &#39;出&#39;变量在remove函数和for循环中都引用。
只需使用
for i in range(len(out)):
out.remove(out[i]);
答案 8 :(得分:0)
首先,您对'#'进行分割以获取每条记录(一串键,值对)。然后,将每个o分割成空格,以提供[key,value]的列表。 dict()
允许您直接从键,值对列表中构建字典。所以:
>>> dict( k_v.split() for k_v in s.split('#')[1:] )
{'one': 'cat', 'two': 'dogs', 'three': 'birds'}
(注意:我们必须使用s.split('#')[1:]
来跳过第一条(空白)记录)