[英]How to convert this tuple list to this dict in a Pythonic way?
我有一個元組列表
tuplist = [('person', u'English : 1, 2, 3 ; Dutch : 5, 6, 7'), ('home', u'English : 8, 9, 10; Dutch: 11, 12, 13')]
我想將其轉換為特定的字典
{'person': {u'Dutch': [u'5', u'6', u'7'], u'English': [u'1', u'2', u'3']}, 'home': {u'Dutch': [u'11', u'12', u'13'], u'English': [u'8', u'9', u'10']}}
目前,我這樣:
dic = dict(tuplist)
final_dic = {}
for x in dic:
str = dic[x]
list1 = [y.strip() for y in str.split(';')]
subdict = {}
for z in list1:
list2 = [y.strip() for y in z.split(':')]
subdict[list2[0]] = [y.strip() for y in list2[1].split(',')]
final_dic[x] = subdict
但我想將其重寫為更多Pythonic。 有人知道嗎?
您可以嵌套一組字典和列表推導:
{k: {l.strip(): [n.strip() for n in nums.split(',')]
for i in v.split(';')
for l, nums in (i.split(':', 1),)}
for k, v in tuplist}
這真是令人難以置信,所以最好將語言字典拆分成生成器:
def language_values(line):
for entry in line.split(';'):
lang, nums = entry.split(':', 1)
yield lang.strip(), [n.strip() for n in nums.split(',')]
{k: dict(language_values(v)) for k, v in tuplist}
任一種都會產生所需的輸出:
>>> {k: {l.strip(): [n.strip() for n in nums.split(',')]
... for i in v.split(';')
... for l, nums in (i.split(':', 1),)}
... for k, v in tuplist}
{'person': {u'Dutch': [u'5', u'6', u'7'], u'English': [u'1', u'2', u'3']}, 'home': {u'Dutch': [u'11', u'12', u'13'], u'English': [u'8', u'9', u'10']}}
>>> def language_values(line):
... for entry in line.split(';'):
... lang, nums = entry.split(':', 1)
... yield lang.strip(), [n.strip() for n in nums.split(',')]
...
>>> {k: dict(language_values(v)) for k, v in tuplist}
{'person': {u'Dutch': [u'5', u'6', u'7'], u'English': [u'1', u'2', u'3']}, 'home': {u'Dutch': [u'11', u'12', u'13'], u'English': [u'8', u'9', u'10']}}
抱歉,@ colicab,我想您知道我提到的很多事情。 只是我開始為您寫一個答案,最后得到了一個更通用的答案,該答案受您的挑戰啟發。 這可能比SO中的大多數答案更個人化,但是我想大多數人都會同意很多事情都是Python的。
什么是pythonic始終值得商extend。 讓我們來看一些Python工具,它們通常被認為是pythonic的(即,在Python腳本中優雅而有用),可以為我們提供幫助。
我會說,最Python化的事情是慷慨地創建函數。 例如,您將有一個數字,用逗號分隔,並且需要將其轉換為int
列表。 我們應該創建一個函數來生成列表:
def parse_numbers(numbers_string):
pass
# Little assert to ensure it works
assert parse_numbers('1, 2, 3') == [1, 2, 3]
好的,我們的函數暫時不執行任何操作,但是我們可以使用...
str.split()
( 文檔 ) str.strip()
( 文檔 ) int()
構造函數( 文檔 ) 我們可以使用str.split()
方法輕松獲取逗號之間的字符串列表:
>>> "1, 2, 3".split(',')
['1', ' 2', ' 3']
但是,這(單獨)不能解決我們的問題。 首先,因為列表中的字符串具有空格。 可以使用str.strip()
方法解決此問題:
>>> ' 1 '.strip()
'1'
當然,我們更接近int
的列表,但還不存在。 畢竟, '1'
是一個包含數字而不是整數的字符串 (並且在Python中是完全不同的東西 )。 當然,我們可以使用int()
構造函數輕松解決它:
>>> int('1')
1
>>> int(' 1 '.strip())
1
現在,如何將這個操作應用於下面列表中的所有字符串?
很多時候,您將需要從其他列表創建列表。 在其他地方,我們用於創建一個空列表,並在其中填充內容。 但是, pythonic方式涉及列表 推導 。 例如,下面的行將獲取分割后的每個元素,從中剝離所有空白,剝離后的結果將轉換為int
。 畢竟,這些操作的結果將被放入一個新列表中:
>>> [int(n.strip()) for n in '1, 2 , 3 '.split(',')]
[1, 2, 3]
對numbers_string
參數應用相同的邏輯,我們可以得到下面的漂亮函數:
def parse_numbers(numbers_string):
return [int(n.strip()) for n in numbers_string.split(',')]
# Little assert to ensure it works
assert parse_numbers('1, 2, 3') == [1, 2, 3]
簡單,內聚,清晰-實際上是pythonic。
現在,我們該怎么辦? 我們應該獲得語言名稱和數字列表。 為此,我們回到第一個答案:函數! 但是要使其正常工作,我們將使用非常pythonic ...
我們的下一個函數將使用類似於'English : 1, 2
的字符串'English : 1, 2
並返回適合在字典構造器中使用的對:
def parse_language(language_string):
language, numbers_string = language_string.split(':')
return language.strip(), parse_numbers(numbers_string)
# Little assert to ensure it works
assert parse_language('English : 1, 2, 3') == ('English', [1, 2, 3])
我們已經知道了strip()
和split()
。 新的魔術是split(':')
調用將返回帶有兩個值的列表-我們可以通過一次賦值將它們放入兩個變量中:
language, numbers_string = language_string.split(':')
這稱為解壓縮 ,並且非常pythonic。 另外,請注意, return
命令后面是兩個值,兩個值之間用逗號分隔。 結果將是一個包含兩個值的tuple
類型的值:
>>> parse_language('English : 1, 2, 3')
('English', [1, 2, 3])
兩個值成為唯一元組的過程稱為包裝 。
僅當每個字符串只有一種語言時...但是,每個字符串有多種語言,例如'English : 1, 2, 3 ; Dutch : 5, 6, 7'
'English : 1, 2, 3 ; Dutch : 5, 6, 7'
。 但是我們知道解決方案,對不對? 是的,一個新功能! 現在,使用我們學到的所有知識: split()
, strip()
,列表推導...
def split_languages(languages):
return [language.strip() for language in languages.split(';')]
# Little assert to ensure it works
assert (
split_languages('English : 1, 2; Dutch : 5, 7') ==
['English : 1, 2', 'Dutch : 5, 7']
)
當然,我們只得到一個字符串列表,而不是字典。 使用非常pythonic很容易解決...
dict
構造函數( 文檔 , 文檔 ) 如您現在所見,可以通過{key: value ...}
語法或通過dict()
構造函數來創建dict()
。 構造函數有一些非常酷的行為。 其中之一是從成對的列表中創建字典。 考慮以下列表:
>>> l = [('key-1', 0), ('key-2', 'value'), ('key-3', 2)]
如果將其傳遞給dict構造函數,我們將獲得如下所示的dict:
>>> dict(l)
{'key-3': 2, 'key-2': 'value', 'key-1': 0}
這就是parse_language()
返回一個元組的原因:我們可以使用它來創建鍵對值。 通過生成器表達式 (一種更高級,更高效的列表理解)和dict構造函數使用它,我們可以通過以下方式從字符串中獲取所有語言:
def parse_languages(languages):
return dict(
parse_language(language)
for language in split_languages(languages)
)
# You know, let's assure everything is until now
assert (
parse_languages('English : 1, 2; Dutch : 5, 7') ==
{
'English' : [1, 2],
'Dutch' : [5, 7]
}
)
假設每個類別都有一個名稱(例如“ person”或“ home”)和一個可由parse_languages()
解析的“語言字符串”,我們接下來的parse_languages()
步驟是使用...
實際上,這個新功能不會有什么好消息:打開包裝足以節省一天的時間:
def parse_category(category_tuple):
category, languages = category_tuple
return category, parse_languages(languages)
# It is pythonic to test your functions, too! As you can see, asserts
# can help on it. They are not very popular, however... Go figure.
assert (
parse_category( ('person', 'English : 1, 2; Dutch : 5, 7') ) ==
(
'person',
{
'English' : [1, 2],
'Dutch' : [5, 7]
}
)
)
請注意,我們的parse_category()
函數返回一個元組。 這是因為我們可以使用生成器表達式加上dict構造函數從輸入的所有元組創建一個dict。 這樣,我們可以產生一個非常優雅的pythonic函數:
def parse_tuples(tuples):
return dict(parse_category(category) for category in tuples)
# No assert now. I have typed too much, I need some coffee :(
但是,我們將在這里放置很多功能嗎? 在有史以來最Python化的事情之一中:
就我而言,我將所有內容保存在名為langparse.py
的文件中。 現在,我可以導入它並調用我們的parse_tuples()
函數:
>>> import langparse
>>> tuplist = [('person', u'English : 1, 2, 3 ; Dutch : 5, 6, 7'), ('home', u'English : 8, 9, 10; Dutch: 11, 12, 13')]
>>> langparse.parse_tuples(tuplist)
{'person': {u'Dutch': [5, 6, 7], u'English': [1, 2, 3]}, 'home': {u'Dutch': [11, 12, 13], u'English': [8, 9, 10]}}
當然,在終端中調用它只是為了測試,但是天空是極限。 由於它在模塊中,因此我可以在其他地方使用所有函數。 模塊是如此的pythonic,以至於Python Zen中的最后一行是對它們的致敬:
命名空間是一個很棒的主意-讓我們做更多這些吧!
當然,不僅對於他們來說,模塊當然是Python中最重要的命名空間之一。
“好吧,”我聽到您在想,“這一切都很酷,而且很好,但是我只想編寫一個(雖然有些復雜)腳本!現在我該怎么辦,編寫另一個文件來調用我的模塊?” 一點也不,我的朋友! 您只需要使用...
__name__ == "__main__"
慣用語 在python中,您可以從__name__
變量中檢索模塊的名稱。 它始終是模塊的名稱...除了一個例外:如果直接調用該模塊(而不是導入),則__name__
的值為"__main__"
。 例如,如果我創建了一個簡單的模塊:
$ echo 'print(__name__)' > mymod.py
...並將其導入,輸出將為其名稱:
$ python -c'導入mymod'mymod
但是,如果我直接執行mymod.py
,則輸出為__main__
:
$ python mymod.py
__main__
因此,我們可以在模塊末尾添加以下行。 現在,如果直接調用它,它將始終執行代碼,但是如果導入模塊,則永遠不會執行:
if __name__ == "__main__":
tuplist = [
('person', u'English : 1, 2, 3 ; Dutch : 5, 6, 7'),
('home', u'English : 8, 9, 10; Dutch: 11, 12, 13')
]
print parse_tuples(tuplist)
讓我們看看? 這是我的機器中的結果:
$ python langparse.py
{'person': {u'Dutch': [5, 6, 7], u'English': [1, 2, 3]}, 'home': {u'Dutch': [11, 12, 13], u'English': [8, 9, 10]}}
Python有很多很棒的東西,使編程成為一項了不起的任務。 其中包括有用的方法,模塊,列表,元組,字典,列表理解(以及生成器表達式和dict生成器!),解包……學習所有這些習語將使一切變得更容易。 但是,如果只需要使用一件事,請使用功能和模塊。 即使創建過多它們,合並它們也比拆分要容易。
而且,畢竟,如果您不確定該怎么做,請記住我們的最高指南Python之禪 。 是的,這有點幽默,但這也是真實的。
完整的腳本可以在Pastebin中看到。
def dictify(s):
return dict((v.split(":",1)[0],v.split(":",1)[1].split(",")) for v in s.split(";"))
dict((x[0],dictify(x[1])) for x in my_tuple)
我可能會怎么做...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.