如何将变量形状嵌套列表复制到固定形状列表

时间:2018-06-09 06:34:34

标签: python python-3.x graph

基本上,我试图用填充,填充可变长度输入。

  

鉴于

     

假设变量形状列表是

seq = [[[1,2,3], [4,5,6,7]],
       [[1], ],
       [[7,8,9], [10,11]]]
     

零的固定形状列表的形状为[3, 2, 4]

fixed_list = [[[0, 0, 0, 0], [0, 0, 0, 0]],
              [[0, 0, 0, 0], [0, 0, 0, 0]],
              [[0, 0, 0, 0], [0, 0, 0, 0]]]
     

输出:

     

所需的输出是从变量形状列表到其的副本   固定形状列表中的相应尺寸

output = [[[1, 2, 3, 0], [4, 5, 6, 7]],
          [[1, 0, 0, 0], [0, 0, 0, 0]],
          [[7, 8, 9, 0], [10, 11, 0, 0]]]

是否有任何递归方式来实现复制过程?

只是一个小小的通知:这只是一个具体的例子,可以有更多其他固定形状,即[3,2,5,6,7][3,4]用于其他一些序列示例。

编辑:

序列也可以是,

seq = [[1,4,5,7],
       [2,8],
       [6,3,2]]

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

的形状为[3,4],填充预计也将在此推广。

编辑:

这是我生成fixed_list作为对评论的回应的编码。

def _dfs_max_len(seqs: list, layers: defaultdict, count=0):
    try:
        len_ = len(seqs)
        if len_ > layers[count]:
            layers[count] = len_
        count += 1
    except TypeError:
        return

    for i in range(len_):
        _dfs_max_len(seqs[i], layers, count)

def get_seqs_shape(seqs: list):
    shape = defaultdict(int)
    _dfs_max_len(seqs, shape)

    return list(shape.values()) # won't need `list` for python2 

def zeros_list(shape: list):
    if len(shape) == 1:
        return [0 for _ in range(shape[0])]

    curnt_shape = shape[0]
    sublist = zeros_list(shape[1:])
    return [sublist for _ in range(curnt_shape)]

shape = get_seqs_shape(seq)
zeros = zeros_list(shape)

2 个答案:

答案 0 :(得分:1)

这是一个半递归解决方案,第一个实际用零填充,第二个嵌入现有的零块(或其他值)。

import itertools as it

def subdims(L):
    """determine the depth and max dimensions of a nested list"""
    SL = (subdims(S) for S in L if isinstance(S, list))
    return (len(L), *map(max, it.zip_longest(*SL, fillvalue=0)))

def pad(L, dims):
    """zero-pad a nested list to flush faces"""
    d, *sdims = dims
    L = it.chain(L, it.repeat(0, d-len(L))) if L else it.repeat(0, d)
    return list(map(pad, L, it.repeat(sdims)) if sdims else L)

def py_zeros(dims):
    """create an nd block (a nested list) of zeros"""
    d, *sdims = dims
    return [py_zeros(sdims) if sdims else 0 for _ in range(d)]

def embed(L, Z):
    """copy a nested list into another large enough nested list"""
    for i, x in enumerate(L):
        if isinstance(x, list):
            embed(x, Z[i])
        else:
            Z[i] = x

演示:

# pad directly or ...
>>> pad(seq, subdims(seq))
[[[1, 2, 3, 0], [4, 5, 6, 7]], [[1, 0, 0, 0], [0, 0, 0, 0]], [[7, 8, 9, 0], [10, 11, 0, 0]]]
>>> 

# ... create a block of zeros and ...
>>> py_zeros(subdims(seq))
>>> Z = py_zeros(subdims(seq))
[[[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]]

# ... copy there
>>> embed(seq, Z)
>>> Z
[[[1, 2, 3, 0], [4, 5, 6, 7]], [[1, 0, 0, 0], [0, 0, 0, 0]], [[7, 8, 9, 0], [10, 11, 0, 0]]]

答案 1 :(得分:0)

朴素的非递归解决方案:尝试更新每个索引,中​​断错误。如果提前知道fixed_list的形状,则可以避免调用shape。请注意,这是在fixed_list上进行的。

seq = [[[1, 2, 3], [4, 5, 6, 7]], [[1]], [[7, 8, 9], [10, 11]]]

fixed_list = [
    [[0, 0, 0, 0], [0, 0, 0, 0]],
    [[0, 0, 0, 0], [0, 0, 0, 0]],
    [[0, 0, 0, 0], [0, 0, 0, 0]],
]

from itertools import product


def shape(xs):
    sh = list()
    while type(xs) is list:
        sh.append(len(xs))
        xs = xs[0]

    return sh


def upd(template, content):
    sh = shape(template)
    for ix in product(*map(range, sh)):
        temp = template
        con = content

        for i in ix[:-1]:
            try:
                temp = temp[i]
                con = con[i]
            except:
                break
        else:
            temp[: len(con)] = con[:]


upd(fixed_list, seq)