[英]How to transform string of space-separated key,value pairs of unique words into a dict
我有一個字符串,其中的單詞用空格分隔(所有單詞都是唯一的,沒有重復)。 我將此字符串轉換為列表:
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個項目。
至於for循環中實際發生的事情:
從 Python for語句文檔 :
表達式列表評估一次 ; 它應該產生一個可迭代的對象。 為
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
希望插圖可以幫助您了解內部發生的事情......
我想你其實想要這樣的東西:
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'}
你不具體。 你為什么要刪除列表中的所有內容? 如果您需要做的只是清除列表,為什么不這樣做:
out = []
您遇到的問題是在迭代時修改列表的結果。 刪除項目后,其后的所有內容都會向前移動一個索引,但迭代器不會考慮更改並繼續增加上次訪問的索引。 迭代器因此會跳過列表中的每個第二個元素,這就是為什么你剩下一半元素的原因。
對您的問題最簡單的直接解決方案是使用切片表示法迭代out
的副本 :
for x in out[:]:
# ...
out.remove(x)
但是,這里有一個更深層次的問題:為什么你需要從列表中刪除項目? 使用您的算法,您可以保證最終得到一個空列表,這對您沒用。 在不刪除項目的情況下迭代列表會更簡單,更有效。
當您完成列表(在for循環塊之后)時,您可以顯式刪除它(使用del
關鍵字)或者只是將其留給Python的垃圾收集系統來處理。
還有一個問題是:您將列表上的直接迭代與基於索引的引用相結合。 for x in out
的使用通常應限於您希望獨立於其他元素訪問每個元素的情況。 如果要使用索引,請for i in range(len(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]))
我相信你想跟隨。
>>> 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'}
>>>
如果您只需要清除列表,
用out = []
或out.clear()
無論如何,你說的是因為列表的remove
功能影響列表。
out = ['a', 'b', 'c', 'd', 'e', 'f']
for x in out:
out.remove(x)
print(x)
然后結果如下所示:
高手
它正好是完整列表的一半。 所以,在你的情況下,你得到了192(192的一半)。
問題是無論何時從列表中刪除值,該特定列表都會動態恢復其值。 也就是說,當您執行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
問題是你在迭代時使用remove(x)。 'out'變量在remove函數和for循環中都引用。
只是用
for i in range(len(out)):
out.remove(out[i]);
首先,您在'#'上拆分以獲取每條記錄(一串鍵,值對)。 然后你在空間上拆分每個o,給你一個[key,value]列表。 dict()
允許您直接從鍵,值對列表構造dict。 所以:
>>> dict( k_v.split() for k_v in s.split('#')[1:] )
{'one': 'cat', 'two': 'dogs', 'three': 'birds'}
(注意:我們必須使用s.split('#')[1:]
跳過第一個(空白)記錄)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.