将字典列表转换为命名元组列表的 Pythonic 方法

发布于 2024-12-10 22:43:40 字数 936 浏览 0 评论 0原文

我有一个 dictlist。需要将其转换为 namedtuplelist(首选)或简单的 tuple,同时用空格分割第一个变量。

还有什么更Python式的方法吗?

我稍微简化了我的代码。欢迎理解、gen 表达式和 itertools 使用。

数据输入:

dl = [{'a': '1 2 3',
       'd': '*',
       'n': 'first'},
      {'a': '4 5',
       'd': '*', 'n':
       'second'},
      {'a': '6',
       'd': '*',
       'n': 'third'},
      {'a': '7 8 9 10',
       'd': '*',
       'n': 'forth'}]

简单算法:

from collections import namedtuple

some = namedtuple('some', ['a', 'd', 'n'])

items = []
for m in dl:
    a, d, n = m.values()
    a = a.split()
    items.append(some(a, d, n))

输出:

[some(a=['1', '2', '3'], d='*', n='first'),
 some(a=['4', '5'], d='*', n='second'),
 some(a=['6'], d='*', n='third'),
 some(a=['7', '8', '9', '10'], d='*', n='forth')]

I have a list of dict. Need to convert it to list of namedtuple(preferred) or simple tuple while to split first variable by whitespace.

What is more pythonic way to do it?

I simplified my code a little. Comprehensions, gen expressions and itertools usage welcomed.

Data-in:

dl = [{'a': '1 2 3',
       'd': '*',
       'n': 'first'},
      {'a': '4 5',
       'd': '*', 'n':
       'second'},
      {'a': '6',
       'd': '*',
       'n': 'third'},
      {'a': '7 8 9 10',
       'd': '*',
       'n': 'forth'}]

Simple algorithm:

from collections import namedtuple

some = namedtuple('some', ['a', 'd', 'n'])

items = []
for m in dl:
    a, d, n = m.values()
    a = a.split()
    items.append(some(a, d, n))

Output:

[some(a=['1', '2', '3'], d='*', n='first'),
 some(a=['4', '5'], d='*', n='second'),
 some(a=['6'], d='*', n='third'),
 some(a=['7', '8', '9', '10'], d='*', n='forth')]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉鱼一梦 2024-12-17 22:43:40

下面,@Petr Viktorin 指出了我原来的答案和您最初的解决方案的问题:

警告!字典的values()没有任何特定的顺序!如果这个解决方案有效,并且 a、d、n 确实按该顺序返回,那么这只是一个巧合。如果您使用不同版本的 Python 或以不同的方式创建字典,它可能会崩溃。

(我有点羞愧,我没有一开始就选择这个,并获得了 45 名代表!)

请改用 @eryksun 的建议:

items =  [some(m['a'].split(), m['d'], m['n']) for m in dl]

我原来的错误答案。除非您有 OrderedDict 列表,否则请勿使用它。

items =  [some(a.split(), d, n) for a,d,n in (m.values() for m in dl)]

Below, @Petr Viktorin points out the problem with my original answer and your initial solution:

WARNING! The values() of a dictionary are not in any particular order! If this solution works, and a, d, n are really returned in that order, it's just a coincidence. If you use a different version of Python or create the dicts in a different way, it might break.

(I'm kind of mortified I didn't pick this up in the first place, and got 45 rep for it!)

Use @eryksun's suggestion instead:

items =  [some(m['a'].split(), m['d'], m['n']) for m in dl]

My original, incorrect answer. Don't use it unless you have a list of OrderedDict.

items =  [some(a.split(), d, n) for a,d,n in (m.values() for m in dl)]
高跟鞋的旋律 2024-12-17 22:43:40

我想我会在这里插话只是因为我非常喜欢命名元组和字典!

这是一个包含字典理解的列表理解,它可以对字典进行初始处理:

split_dictionaries = \ 
    [{key: value.split() for k, value in d.iteritems()} for d in dl] 

我经常使用一个我称之为“tupperware”的配方,它递归地将字典转换为命名元组。有关代码,请参阅此处的要点。这是其中的一个简化部分,可以集成到这里,并有一个非常干净的方法来执行此操作。

import collections

def namedtuple_from_mapping(mapping, name="Tupperware"):
    this_namedtuple_maker = collections.namedtuple(name, mapping.iterkeys())
    return this_namedtuple_maker(**mapping)

因此,给定该函数,您可以执行此操作 - 我们将很快重构:

split_namedtuples = [ 
    namedtuple_from_mapping(
        {key: value.split() for k, value in d.iteritems()}
    ) for d in dl
]   

现在具有更好的封装性和可读性:

def format_string(string):
    return string.split()

def format_dict(d):
    return {key: format_string(value) for key, value in d.iteritems()}

formatted_namedtuples = [namedtuple_from_mapping(format_dict(d)) for d in dl]

Thought I'd chime in here just because I love namedtuples and dictionaries so much!

Here's a list comprehension with a dict comprehension in it, that can do your initial processing of the dictionary:

split_dictionaries = \ 
    [{key: value.split() for k, value in d.iteritems()} for d in dl] 

I frequently use a recipe that I call "tupperware" that recursively converts dictionaries to namedtuples. See the gist here, for the code. Here's a simplified piece of it, to integrate here, and have a pretty clean way of doing this operation.

import collections

def namedtuple_from_mapping(mapping, name="Tupperware"):
    this_namedtuple_maker = collections.namedtuple(name, mapping.iterkeys())
    return this_namedtuple_maker(**mapping)

So given that function, you can do this - which we'll refactor shortly:

split_namedtuples = [ 
    namedtuple_from_mapping(
        {key: value.split() for k, value in d.iteritems()}
    ) for d in dl
]   

And now with better encapsulation and readability:

def format_string(string):
    return string.split()

def format_dict(d):
    return {key: format_string(value) for key, value in d.iteritems()}

formatted_namedtuples = [namedtuple_from_mapping(format_dict(d)) for d in dl]
oО清风挽发oО 2024-12-17 22:43:40

另外@detly提供的答案,如果您事先不知道字典的字段,您可以构造一个 namedtuple

some = namedtuple('some', set(k for k in d.keys() for d in dl))

In addition the answer provided by @detly, if you don't know about the fields of the dicts before hand, you can construct a namedtuple class with

some = namedtuple('some', set(k for k in d.keys() for d in dl))
梦年海沫深 2024-12-17 22:43:40

另一种选择,不确定它比其他选项更好还是更差:

class some(namedtuple('some', 'a d n')):
    def __new__(cls, **args):
        args['a'] = args['a'].split()
        return super(some, cls).__new__(cls, **args)

items = list(some(**m) for m in dl)

顺便说一句,我并不绝对致力于为基类提供与子类 some 相同的名称。我喜欢它,因为它意味着生成的类使用名称 some 转换为字符串,并且它从来没有给我带来特别的问题,但如果您使用类名进行调试,它可能会令人困惑。所以一定要小心。

或者使用不同技巧的相同想法:

some = namedtuple('some', 'a d n')

def make_some(args):
    args = args.copy()
    args['a'] = args['a'].split()
    return some(**args)

items = map(make_some, dl) # NB: this doesn't return a list in Python 3

Another option, not sure whether it's better or worse than the others:

class some(namedtuple('some', 'a d n')):
    def __new__(cls, **args):
        args['a'] = args['a'].split()
        return super(some, cls).__new__(cls, **args)

items = list(some(**m) for m in dl)

BTW, I'm not absolutely committed to giving the base class the same name as the subclass some. I like it because it means that the resulting class converts to string using the name some, and it's never particularly caused me problems, but potentially it could be confusing if you're debugging with class names. So do it with care.

Or the same idea using different tricks:

some = namedtuple('some', 'a d n')

def make_some(args):
    args = args.copy()
    args['a'] = args['a'].split()
    return some(**args)

items = map(make_some, dl) # NB: this doesn't return a list in Python 3
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文