Python 解压命名元组的二维列表

发布于 2024-11-28 07:32:52 字数 1617 浏览 5 评论 0原文

我有一个命名元组的二维列表(假设每个元组有 N 个值),我想将它们解包到 N 个不同的二维列表中,其中每个解包的二维列表完全由来自原始清单。例如,如果我有这个二维列表:

>>> combo = namedtuple('combo', 'i, f, s')
>>> combo_mat = [[combo(i + 3*j, float(i + 3*j), str(i + 3*j)) for i in range(3)]
                 for j in range(3)]
>>> combo_mat
[[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')],
 [combo(i=3, f=3.0, s='3'), combo(i=4, f=4.0, s='4'), combo(i=5, f=5.0, s='5')],
 [combo(i=6, f=6.0, s='6'), combo(i=7, f=7.0, s='7'), combo(i=8, f=8.0, s='8')]]

我希望 3 个结果是:

[[0, 1, 2],
 [3, 4, 5],
 [6, 7, 8]]

[[0.0, 1.0, 2.0],
 [3.0, 4.0, 5.0],
 [6.0, 7.0, 8.0]]

[['0', '1', '2'],
 ['3', '4', '5'],
 ['6', '7', '8']]

如果我只有一个一维元组列表,我会使用 zip(*mylist),例如:

>>> zip(*[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')])
[(0, 1, 2), (0.0, 1.0, 2.0), ('0', '1', '2')]

我可以通过嵌套将其扩展到我的情况:

>>> zip(*[zip(*combs) for combs in combo_mat])
[((0, 1, 2),
  (3, 4, 5),
  (6, 7, 8)),
 ((0.0, 1.0, 2.0),
  (3.0, 4.0, 5.0),
  (6.0, 7.0, 8.0)),
 (('0', '1', '2'),
  ('3', '4', '5'),
  ('6', '7', '8'))]

但这并没有给我想要的列表,并且嵌套解包 zip(*) 函数不那么可读。有人对更Pythonic的解决方案有什么想法吗?如果您可以在最终结果中的某个位置处理元组属性的名称,那就加分了。

实际上,现在我想起来了,如果我能有一个将元组属性的名称映射到其各自矩阵的字典,那就太理想了,例如:

{'i': [[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]], 
 'f': [[0.0, 1.0, 2.0],
       [3.0, 4.0, 5.0],
       [6.0, 7.0, 8.0]]
 's': [['0', '1', '2'],
       ['3', '4', '5'],
       ['6', '7', '8']]}

I have a 2-dimensional list of named tuples (let's say that each tuple has N values), and I want to unpack them into N different 2-dimensional lists where each unpacked 2-D list is composed entirely of a single attribute from the original list. For example if I have this 2-D list:

>>> combo = namedtuple('combo', 'i, f, s')
>>> combo_mat = [[combo(i + 3*j, float(i + 3*j), str(i + 3*j)) for i in range(3)]
                 for j in range(3)]
>>> combo_mat
[[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')],
 [combo(i=3, f=3.0, s='3'), combo(i=4, f=4.0, s='4'), combo(i=5, f=5.0, s='5')],
 [combo(i=6, f=6.0, s='6'), combo(i=7, f=7.0, s='7'), combo(i=8, f=8.0, s='8')]]

I'd like the 3 results to be:

[[0, 1, 2],
 [3, 4, 5],
 [6, 7, 8]]

[[0.0, 1.0, 2.0],
 [3.0, 4.0, 5.0],
 [6.0, 7.0, 8.0]]

[['0', '1', '2'],
 ['3', '4', '5'],
 ['6', '7', '8']]

If I just had a 1-dimensional list of tuples I'd use zip(*mylist), like:

>>> zip(*[combo(i=0, f=0.0, s='0'), combo(i=1, f=1.0, s='1'), combo(i=2, f=2.0, s='2')])
[(0, 1, 2), (0.0, 1.0, 2.0), ('0', '1', '2')]

And I can extend this to my situation just by nesting:

>>> zip(*[zip(*combs) for combs in combo_mat])
[((0, 1, 2),
  (3, 4, 5),
  (6, 7, 8)),
 ((0.0, 1.0, 2.0),
  (3.0, 4.0, 5.0),
  (6.0, 7.0, 8.0)),
 (('0', '1', '2'),
  ('3', '4', '5'),
  ('6', '7', '8'))]

But this doesn't give me the lists I wanted, and nested unpacking zip(*) functions isn't that readable. Anyone have any ideas for a more pythonic solution? Bonus points if you can work the names of the tuples' attributes in there somewhere in the end result.

Actually, now that I think of it, it would be ideal if I could have a dict that mapped the name of the tuple attribute to its respective matrix, like:

{'i': [[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]], 
 'f': [[0.0, 1.0, 2.0],
       [3.0, 4.0, 5.0],
       [6.0, 7.0, 8.0]]
 's': [['0', '1', '2'],
       ['3', '4', '5'],
       ['6', '7', '8']]}

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

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

发布评论

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

评论(4

中性美 2024-12-05 07:32:52

函数式编程可以拯救你吗?它本质上是嵌套拉链的更清晰版本:

def fmap_element(f, el):
    return f(el)

def fmap_list(f, l):
    return [fmap_element(f, el) for el in l)]

def fmap_lol(f, lol):
    return [fmap_list(f,l) for l in lol]

def split_nt_lol(nt_lol):
    return dict((name, fmap_lol(lambda nt: getattr(nt, name), nt_lol)) 
                for name in nt_lol[0][0]._fields)

用法:

>>> split_nt_lol(combo_mat)
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
 's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
 'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]}

Functional programming to the rescue? It's essentially a cleaner version of nesting the zips:

def fmap_element(f, el):
    return f(el)

def fmap_list(f, l):
    return [fmap_element(f, el) for el in l)]

def fmap_lol(f, lol):
    return [fmap_list(f,l) for l in lol]

def split_nt_lol(nt_lol):
    return dict((name, fmap_lol(lambda nt: getattr(nt, name), nt_lol)) 
                for name in nt_lol[0][0]._fields)

Usage:

>>> split_nt_lol(combo_mat)
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
 's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
 'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]}
南薇 2024-12-05 07:32:52
matrices = {}

for num, name in enumerate(combo._fields):
    matrix = []
    for i in combo_mat:
        row = []
        for j in i:
            row.append(j[num])
        matrix.append(row)
    matrices[name] = matrix
matrices = {}

for num, name in enumerate(combo._fields):
    matrix = []
    for i in combo_mat:
        row = []
        for j in i:
            row.append(j[num])
        matrix.append(row)
    matrices[name] = matrix
将军与妓 2024-12-05 07:32:52

这并不比嵌套的 zip(*) 函数更具可读性,但它完成了工作:

>>> dict((key, [[c._asdict()[key] for c in combos] for combos in combo_mat])
         for key in ['i', 'f', 's'])
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
 's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
 'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]}

我想你可以让它更容易阅读,如下所示:

def get_mat(combo_mat, key):
    return [[c._asdict()[key] for c in combos] for combos in combo_mat]

def get_mat_dict(combo_mat, keys):
    return dict((key, get_mat(combo_mat, key)) for key in keys)

This isn't any more readable than nested zip(*) functions, but it does the job:

>>> dict((key, [[c._asdict()[key] for c in combos] for combos in combo_mat])
         for key in ['i', 'f', 's'])
{'i': [[0, 1, 2], [3, 4, 5], [6, 7, 8]], 
 's': [['0', '1', '2'], ['3', '4', '5'], ['6', '7', '8']], 
 'f': [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]}

I suppose you could make it a bit easier to read like so:

def get_mat(combo_mat, key):
    return [[c._asdict()[key] for c in combos] for combos in combo_mat]

def get_mat_dict(combo_mat, keys):
    return dict((key, get_mat(combo_mat, key)) for key in keys)
风吹短裙飘 2024-12-05 07:32:52

这可以通过使用 transpose() 转置数组来简单地实现。

参考:
http://www.astro.ufl.edu/~warner/prog/python .html(搜索单词“transpose”)

This can be simply achieved by transposing the array, using transpose().

Reference:
http://www.astro.ufl.edu/~warner/prog/python.html (search for the word "transpose")

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文