0

好吧,我是 Python 新手,正在学习元组和列表。我被要求创建一个程序,但这涉及转换以下列表:

    li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]

在一个看起来像这样的列表中:

    li = [[(1,2,3),(4,5,6)],[(7,8,9),(10,11,12)],[(13,14,15),(16,17,18)]

基本上,从一个简单的列表到一个包含子列表的列表,其中包含两个包含 3 个元素的元组。

我感谢您的帮助。

谢谢。

4

4 回答 4

2

解决这个问题的简单方法是分两步完成:首先,将其分解为一个 3 元组列表。然后,将其分解为 2 个列表。

每个步骤有两种方法。


首先是使用切片和测距:

>>> li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
>>> [li[i:i+3] for i in range(0, len(li), 3)]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]

但是我们想要 3 元组,而不是 3 列表,所以我们需要tuple()在表达式周围添加一个:

>>> li_3 = [tuple(li[i:i+3]) for i in range(0, len(li), 3)]

然后,我们再次做同样的事情:

>>> li_23 = [li_3[i:i+2] for i in range(0, len(li_3), 2)]

另一种方法是将相同的迭代器压缩到自身。文档中的itertools食谱显示了如何做到这一点。其实我们只要把菜谱复制粘贴一下,就可以使用了。

>>> from itertools import izip_longest
>>> def grouper(iterable, n, fillvalue=None):
...    "Collect data into fixed-length chunks or blocks"
...    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
...    args = [iter(iterable)] * n
...    return izip_longest(fillvalue=fillvalue, *args)

现在:

>>> li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
>>> grouper(li, 3)
<itertools.zip_longest at 0x10467dc00>

它给了我们一个迭代器;我们必须把它变成一个列表才能看到元素:

>>> list(grouper(li, 3))
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]

所以,现在我们只需重复相同的步骤:

>>> list(grouper(grouper(li, 3), 2))
[((1, 2, 3), (4, 5, 6)), ((7, 8, 9), (10, 11, 12)), ((13, 14, 15), (16, 17, 18))]

除了我们得到元组的元组,我们想要元组的列表,所以:

>>> li_23 = [list(group) for group in grouper(grouper(li, 3), 2)]

在 Python 中应该有一种而且只有一种明显的方式来做事。那么,它是什么?

  • 第一个需要一个列表或其他序列;第二个需要任何可迭代的。
  • 如果最后有剩余值,则第一个为您提供部分组;第二个填充最后一组。
  • 第二个很容易修改以删除不完整的最后一组而不是填充它,并且修改给您部分组也不难;第一个更难修改。
  • 第一个对于新手来说更容易理解,但一旦你掌握了这个概念,可能就更难阅读了。
  • 任何一个都可以很容易地包装在一个函数中,但第二个已经为你包装在食谱(或more_itertools第三方包)中。

这些差异之一通常对您的用例很重要,在这种情况下,显而易见的方法就是做您想做的事。对于像这样的简单案例,这些都无关紧要……做任何一个你觉得更易读的案例。

于 2013-09-26T23:00:05.100 回答
2

我个人喜欢这种方法:

>>> li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
>>> 
>>> v = iter(li)
>>> li = [(i, next(v), next(v)) for i in v]  # creates list of tuples
>>> 
>>> v = iter(li)
>>> li = [[i, next(v)] for i in v]  # creates list of lists of tuples
>>> 
>>> li
[[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), (10, 11, 12)], [(13, 14, 15), (16, 17, 18)]]

顺便说一句,如果元素不适合这种结构,这将引发错误,例如考虑:

>>> l = [1, 2, 3]
>>> v = iter(l)
>>> 
>>> [(i, next(v)) for i in v]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

这可能合适,也可能不合适。

如果不是,简单的解决方法是给出next()第二个参数:

>>> l = [1, 2, 3]
>>> v = iter(l)
>>> 
>>> [(i, next(v, None)) for i in v]
[(1, 2), (3, None)]

参考:

于 2013-09-26T23:01:20.423 回答
1

使用zip()

>>> [zip(*[iter(sub)]*3) for sub in zip(*[iter(li)]*6)]
[[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), (10, 11, 12)], [(13, 14, 15), (16, 17, 18)]]
于 2013-09-26T22:57:02.913 回答
0

给定

li = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]

您可以将项目分组zip(*[iter(li)]*3)

zip(*[iter(li)]*3)
#>>> <zip object at 0x7f0a5578ca28>

并检查:

list(zip(*[iter(li)]*3))
#>>> [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15), (16, 17, 18)]

然后你可以zip(*[...]*2)zip(*[iter(li)]*3)

zip(*[zip(*[iter(li)]*3)]*2)
#>>> <zip object at 0x7f0a5578c998>

并检查:

list(zip(*[zip(*[iter(li)]*3)]*2))
#>>> [((1, 2, 3), (4, 5, 6)), ((7, 8, 9), (10, 11, 12)), ((13, 14, 15), (16, 17, 18))]

内部项目不是一个列表,所以map它是一个:

map(list, zip(*[zip(*[iter(li)]*3)]*2))
#>>> <map object at 0x7f0a5afd80d0>

并检查:

list(map(list, zip(*[zip(*[iter(li)]*3)]*2)))
#>>> [[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), (10, 11, 12)], [(13, 14, 15), (16, 17, 18)]]
于 2013-09-26T23:00:42.393 回答