【问题标题】:Unpacking and re-packing a tuple (Python 2.x)解包和重新打包元组 (Python 2.x)
【发布时间】:2018-02-13 04:07:16
【问题描述】:

我编写了一个函数,它接受、工作并返回简单的非嵌套元组。

例如:

myfun((1,2,3,4)):
... -> logic
return (1,2,3,4) -> the numbers can change, but the shape will be the same

由于该逻辑仅适用于单维元组,但在概念上对于每一级嵌套都是相同的。我想知道是否有办法将像((1,2,(3,)),(4,)) 这样的嵌套元组转换为普通的(1,2,3,4),然后将其转换回((1,2,(3,)),(4,))

基本上我想要的是解压缩一个通用输入元组,使用它,然后将结果打包成与给定一个相同的形状。

有没有 Pythonic 的方式来完成这样的任务?

可能解包可以通过递归解决,但是我不确定“重新打包”部分。

【问题讨论】:

  • 展平部分:stackoverflow.com/questions/2158395/…。在重新打包方面,只需构造元组:((t[0],t[1],(t[2],)),(t[3],))
  • ty,看起来展平部分确实是递归的。但因为它不会保留有关元组原始结构的信息:/

标签: python tuples


【解决方案1】:

拆包并不难:

def unpack(parent):
    for child in parent:
        if type(child) == tuple:
            yield from unpack(child)
        else:
            yield child

例如,可以做到这一点。

重新包装有点棘手。我想出了以下方法,它有效但不是很pythonic,恐怕:

def repack(structured, flat):
    output = []
    global flatlist
    flatlist = list(flat)
    for child in structured:
        if type(child) == tuple:
            output.append(repack(child, flatlist))
        else:
            output.append(flatlist.pop(0))

    return tuple(output)

示例用法是:

nested = ((1, 2, (3,)), (4,))
plain = tuple(unpack(nested))
renested = repack(nested, plain)

希望这会有所帮助!

【讨论】:

  • 确实如此!谢谢。
  • 我的荣幸。可能有一种方法可以在解包时记录结构,然后重新使用该记录的结构来重新打包它而无需递归。有一天可能是一项有趣的运动,但现在该睡觉了。 :-)
  • 是的,这只是保存递归级别的问题......也许我会考虑更多
  • 我认为它不仅仅是简单地保存递归级别,因为给定示例中的 1、2 和 4 具有相同的级别,但不属于一起。当然,除非您还保存了中间的间歇性“跳跃”。
【解决方案2】:

这应该适用于重新包装:

x = (1,(2,3),(4,(5,6)))
y = (9,8,7,6,5,4)

def map_shape(x, y, start=0):
    if type(x) == tuple:
        l = []
        for item in x:
            mapped, n_item = map_shape(item, y[start:])
            start += n_item
            l.append(mapped)
        return tuple(l), start
    else:
        return y[start], start+1

map_shape(x,y)[0]

输出:

(9, (8, 7), (6, (5, 4)))

【讨论】:

  • 我有类似的想法,希望少一些“C-ish”的东西。但这确实是一个解决方案!泰
【解决方案3】:

我提交我的版本。它使用相同的函数来展平和重建列表。如果flatNone,它会变平,否则它会通过产生一个元组来重构。

import collections


def restructure(original, flat=None):
    for el in original:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            if flat:
                yield tuple(restructure(el, flat))
            else:
                yield from restructure(el)
        else:
            yield next(flat) if flat else el


def gen():
    i = 0
    while True:
        yield i
        i += 1


def myfun(iterable):
    flat = tuple(restructure(iterable))
    # your transformation ..
    flat = gen()  # assigning infinite number generator for testing
    return restructure(iterable, flat=iter(flat))


x = (1, (2, 3), (4, (5, 6)))
print(tuple(y for y in myfun(x)))  # (0, (1, 2), (3, (4, 5)))

【讨论】:

  • 非常有趣的想法!
  • 但是...从第 10 行产生的结果是什么?从来没有见过在收益率之后使用的 from。
  • 这是 python 3.x 吗?该死的......我忘了提到我正在使用 2.x
  • 有没有办法将“yield from”转换为 2.x 等价物?
  • 是的,yield fromPEP 380 中引入的表达式,它将让步委托给子生成器。您可以查看Converting “yield from” statement to Python 2.7 code。此外,扁平化部分取自评论部分中发布的Flatten (an irregular) list of lists,并且也是特定于版本的。
猜你喜欢
  • 2013-07-24
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 2013-10-16
  • 2021-10-06
  • 1970-01-01
  • 2019-04-14
  • 1970-01-01
相关资源
最近更新 更多