如何将列表切成不同长度的子列表

Posted

技术标签:

【中文标题】如何将列表切成不同长度的子列表【英文标题】:How to slice a list into sublists with different length 【发布时间】:2022-01-18 13:12:57 【问题描述】:

上下文:我想制作多词搜索网格

我有一个这样的文本行输入(包含数字和字母字符串):

2           <--- tells how many grids/boxes 
3           <--- tells rows/length
4           <--- tells columns/width 
catt        <--\
aata        <--- letters that will fill the box
tatc        <--/
cat         <--- the word that will be search inside the box
5           <--- and repeat but start with the rows
5
gogog
ooooo
godog
ooooo
gogog
dog

所有这些都在一个列表中作为输入

但是,我需要在里面传递变量。所以我假设我需要将列表拆分/切片为另一个列表,其中包含我需要的所有变量。

我想我需要像这样拆分 catdog 的变量:

#variables for cat and dog
rows, cols = [3, 5], [4, 5] #the numbers have to be integer
matrix = [['catt', 'aata', 'tatc'], ['gogog', 'ooooo', 'godog', 'ooooo', 'gogog']]
word = ['cat', 'dog']

这些是我需要的变量。但我不知道如何从上面的输入中拆分它。

如果有任何不同的方式,请随时解释。谢谢

【问题讨论】:

"cattaatatatc" 有一瞬间我以为这是 DNA。但后来一只狗出现了。 【参考方案1】:

我已将您的输入保存在一个名为“input.txt”的文件中,并使用了以下方法:

with open("input.txt", "r") as f:
    lines = [x.strip() for x in f.readlines()]

n_animals, other_lines = int(lines[0]), lines[1:]

rows, cols, matrix, word = [[] for _ in range(4)] # comment by @Stef - well spotted

while len(other_lines) > 0:
    rows.append(int(other_lines[0]))
    cols.append(int(other_lines[1]))
    matrix.append(list(map(lambda x: x[:cols[-1]], other_lines[2:2 + rows[-1]])))
    word.append(other_lines[2 + rows[-1]])
    other_lines = other_lines[2 + rows[-1] + 1:]
    if len(matrix) == n_animals:
        pass # Do we need to take any action here? like break?

print(rows)
print(cols)
print(matrix)
print(word)

输出

[3, 5]
[4, 5]
[['catt', 'aata', 'tatc'], ['gogog', 'ooooo', 'godog', 'ooooo', 'gogog']]
['cat', 'dog']

我的假设是你想用那个 width 变量做点什么,因此我把每个单词都剪成了cols[-1] 个字符。现在,你需要决定如果len(matrix) &gt; n_animals 怎么办。

跟进

结合一些反馈以提高效率:

i = 0
while i < len(other_lines):
    rows.append(int(other_lines[i]))
    cols.append(int(other_lines[i + 1]))
    matrix.append(list(map(lambda x: x[:cols[-1]], other_lines[i + 2 : i + 2 + rows[-1]])))
    word.append(other_lines[i + 2 + rows[-1]])
    i += 2 + rows[-1] + 1
    if len(matrix) == n_animals:
        pass # Do we need to take any action here? like break?

【讨论】:

rows, cols, matrix, word = [[]] * 4 你确定吗?你不想要rows, cols, matrix, word = [[] for _ in range(4)] 吗?否则它是相同空列表的四倍,当您开始修改其中一个空列表时,会发生奇怪的事情。 @Stef 很好看。我被带走了,因为我有rows, cols, matrix, word = [], [], [], [],但建议的方式是错误的。我会采纳你的意见。 +1 还有other_lines = other_lines[2 + rows[-1] + 1:]在while循环中其实代价很大;在 while 循环的每次迭代中,您都在复制所有剩余的行;所以总复杂度是二次的而不是线性的。为了规避这个问题,您可以使用索引i,写作rows.append(int(other_lines[i])),而不是重复地对列表进行切片;或者您可以使用带有next 的迭代器而不是列表。 另外,主循环的停止条件应该基于n_animals! @Stef 好吧,我不知道用例来得出结论。如果我到达n_animals,我应该停下来还是应该做其他事情——以防指定的动物数量超过预期?什么是预期 3 只动物而只指定 2 只?还因为 - 在指定的示例中 - n_animals 无论如何都是一个冗余变量。【参考方案2】:

使用next 遍历文件对象:

with open('input.txt') as f:
    n_animal = int(next(f).strip())
    rows, cols, matrices, words = [], [], [], []
    for _ in range(n_animals):
        n_row = int(next(f).strip())
        n_col = int(next(f).strip())
        rows.append(n_row)
        cols.append(n_col)
        matrix = [list(next(f).strip()) for _ in range(n_row)]
        matrices.append(matrix)
        words.append(next(f).strip())

print('rows, cols = ', rows, cols)
print('matrices = ', matrices)
print('words = ', words)

# rows, cols =  [3, 5] [4, 5]
# matrices =  [[['c', 'a', 't', 't'], ['a', 'a', 't', 'a'], ['t', 'a', 't', 'c']], [['g', 'o', 'g', 'o', 'g'], ['o', 'o', 'o', 'o', 'o'], ['g', 'o', 'd', 'o', 'g'], ['o', 'o', 'o', 'o', 'o'], ['g', 'o', 'g', 'o', 'g']]]
# words =  ['cat', 'dog']

注意:如果可以使用字符串列表而不是列表列表,则可以替换 matrix = 行:

# list of lists
matrix = [list(next(f).strip()) for _ in range(n_row)]

# list of strings
matrix = [next(f).strip() for _ in range(n_row)]

如果您的输入已经存储为字符串列表,而不是要读取的文件,您仍然可以在迭代器上使用 next

lines = ['2', '3', '4', 'catt', ...]

f = iter(lines)

n_animal = int(next(f).strip())
rows, cols, matrices, words = [], [], [], []
for _ in range(n_animals):
    n_row = int(next(f).strip())
    n_col = int(next(f).strip())
    rows.append(n_row)
    cols.append(n_col)
    matrix = [list(next(f).strip()) for _ in range(n_row)]
    matrices.append(matrix)
    words.append(next(f).strip())

【讨论】:

好的答案顺便说一句,但是如果我想让 matrices 像这样 [['catt', 'aata', 'tatc'], ['gogog', 'ooooo', 'godog', 'ooooo', 'gogog']] 怎么办。我试过 splitlines() 但输出是这样的 [[['catt'], ['aata'], ['tatc']], [['gogog'], ['ooooo'], ['godog'], ['ooooo'], ['gogog']]] 。也许你可以帮忙:) @GilangArindawa 我不知道你所说的“我试过 splitlines()”是什么意思。我没有得到和你一样的结果。您是否尝试使用 matrix = [next(f).strip() for _ in range(n_row)] 而不是 matrix = [list(next(f).strip()) for _ in range(n_row)] 哇,这很明显,我没想到,哈哈。谢谢! :D【参考方案3】:

如果每行信息的位置始终是“固定的”,那么最简单的选择是将行转换为列表,然后具体引用每一行。比如:

data = text.splitlines()
grids = data[0]
rows = data[1]
cols = data[2]
letters = data[3:7]
repeat = data[7:9]
remain = data[9:]

print(grids, rows, cols, letters, repeat, remain)

【讨论】:

它不是固定的。重复的次数由写入data[0] 的整数给出。然后在 data[i+1] 处给出字母的行数,其中 i 是您重复的次数。

以上是关于如何将列表切成不同长度的子列表的主要内容,如果未能解决你的问题,请参考以下文章

实际参数列表和形式参数列表的长度错误不同

将列表与列表中不同长度的列表相结合

如何从具有不同长度列表的字典中创建字典列表

如何在不同长度的列表列表中删除最内层的嵌套

如何从 Python 中不同长度的列表列表中创建数据框?

Django:如何从与用户相关的子查询集中获取不同的父列表?