繁体   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