簡體   English   中英

如何以Python方式將此元組列表轉換為該dict?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM