我有一个元组列表
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。有人有想法吗?
答案 0 :(得分:5)
您可以嵌套一组字典和列表推导:
{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']}}
答案 1 :(得分:1)
对不起,@ colicab,我想你知道我提到的很多这些事情。只是我开始给你写一个答案,最后得到了一个受你的挑战启发的更一般的答案。这可能是比大多数人更多的个人答案,但我想大多数人都会认为是pythonic。
什么是 pythonic 总是有争议的。让我们看看Python中的一些工具,通常被认为是pythonic(即在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()
(documentation)str.strip()
(documentation)int()
构造函数(documentation)我们可以使用str.split()
方法轻松获取逗号之间的字符串列表:
>>> "1, 2, 3".split(',')
['1', ' 2', ' 3']
然而,这(单独)并不能解决我们的问题。首先,因为列表中的字符串有空格。可以使用str.strip()
方法解决它:
>>> ' 1 '.strip()
'1'
我们更接近int
的列表,当然,但还没有。毕竟,'1'
是包含数字的字符串,而不是整数(和in Python those are very different things)。当然,我们可以使用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
'等字符串。并返回适合在dict construtor中使用的一对:
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
type的值:
>>> parse_language('English : 1, 2, 3')
('English', [1, 2, 3])
两个值成为唯一元组的过程称为 packing 。
只有我们每个字符串只有语言...但是,我们每个字符串都有各种语言,例如'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
构造函数(documentation,documentation)正如您现在所做的那样,可以通过{key: value ...}
语法或dict()
构造函数创建dicts。构造函数有一些非常酷的行为。其中之一是从对列表中创建dicts。请考虑以下列表:
>>> 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()
返回元组的原因:我们可以使用它来创建键对值。使用generator expressions(一种更高效,更有效的列表理解)和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()
解析,我们的下一个pythonic步骤是使用...
这个新功能实际上不会有好消息:拆包将足以挽救这一天:
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 :(
但是我们会在这里放置这么多功能吗?在有史以来最狂热的事情之一:
就我而言,我将其全部保存在名为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,Zen of Python中的最后一行是对它们的致敬:
命名空间是一个很好的主意 - 让我们做更多的事情!
当然,不仅对他们而言,模块肯定是Python中最重要的命名空间之一。
"嗯,好吧,"我可以听到你的疑惑,"这一切都很酷而且很好,但我只想写一点(但有点复杂)的剧本!我现在应该怎么做,只是为了调用我的模块而写另一个文件?"一点也不,我的朋友!你只需要使用......
__name__ == "__main__"
成语在python中,您可以从__name__
变量中检索模块的名称。它始终是模块的名称......但有一个例外:如果直接调用模块(而不是导入),则__name__
的值将为"__main__"
。例如,如果我创建这样一个简单的模块:
$ echo 'print(__name__)' > mymod.py
...并导入它,输出将是它的名字:
$ python -c' import 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有许多很酷的东西,使编程成为一项非常棒的任务。这些包括有用的方法,模块,列表,元组,dicts,列表推导(以及生成器表达式和字典生成器!),解包...学习所有这些习语将使一切变得更容易。但是,如果您只使用一件事,请使用功能和模块。即使你创建了太多它们,合并它们也比分割更容易。
而且,毕竟,如果你对如何做有疑问,请记住我们的最高指南Zen of Python。是的,这有点幽默,但它也是真实的。
可以看到完整的脚本in Pastebin。
答案 2 :(得分:0)
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)
我可能会这样做......