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