【问题标题】:Dividing a list into subsets according to a numeric array in Python根据Python中的数字数组将列表划分为子集
【发布时间】:2021-09-17 02:39:47
【问题描述】:

我有一个list,其中的字符如下:

s = ['Y', 'U', 'U', 'N', 'U', 'U', 'N', 'N', 'N']

还有以下数组:

t = [2, 4, 3]

我想根据数组划分列表,这样每个子集st[i] 都有len(t[i])。这个例子的结果应该是:

st = [['Y', 'U'], ['U', 'N', 'U', 'U'], ['N', 'N', 'N']]

如果数组 t 是:

t = [5, 2, 2]

那么结果应该是:

st = [['Y', 'U', 'U', 'N', 'U'], ['U', 'N'], ['N', 'N']]

条目是 s 和 t。我正在尝试插入两个循环,一个用于列表 s,另一个用于数组 t。但它不起作用。我该如何实现?

【问题讨论】:

  • {'U','N','U','U'} 不是有效的集合。集合不能有重复的成员。

标签: python string list set


【解决方案1】:

您可以从s 创建一个迭代器,并使用itertools.islice 根据t 中的大小对迭代器进行切片:

from itertools import islice

i = iter(s)
[list(islice(i, l)) for l in t]

这会返回:

[['Y', 'U'], ['U', 'N', 'U', 'U'], ['N', 'N', 'N']]

【讨论】:

  • 绝妙的解决方案!应该被接受:)
  • 非常干净。对 OP 的说明:如果sum(t) > len(s),这将产生空子列表,如果sum(t) < len(s),则不会完全捕获s。一个通用函数可能应该断言sum(t) == len(s)
  • [x for l in (t + [None]) if (x := list(islice(i, l)))] 会处理这两种情况,顺便说一句:D
  • 但这已经接近了“实际上不要那样做”的代码高尔夫水平
【解决方案2】:

对于[2, 4, 3] 的输入,起始索引为:

  • 0
  • 0 + 2 = 2
  • 0 + 2 + 4 = 6

您可以使用itertools.accumulate() 来收集起始索引。

一旦知道起始索引,我们只需通过zip() 将它们与每个起始索引分组的项目数配对,这已经是列表[2, 4, 3] 的内容。因此:

  • 从 0 开始:计数 2
  • 开始 2:计数 4
  • 开始 6:计数 3

或者像 cmets 中提到的 @don'ttalkjustcode 一样,我们也可以跟踪累积的停止索引:

  • 开始(2 - 2 = 0):停止 2
  • 开始 (6 - 4 = 2) : 停止 6
  • 开始(9 - 3 = 6):停止 9
from itertools import accumulate

s = ['Y', 'U', 'U', 'N', 'U', 'U', 'N', 'N', 'N']

for t in [
    [2, 4, 3],
    [5, 2, 2],
    [1, 2, 6],
    [6, 1, 2],
    [2, 1, 4, 3],
    [2, 1, 2, 2, 1, 1],
]:
    # Option 1: Using start/count logic
    z = [s[start:start+count] for start, count in zip(accumulate([0] + t), t)]

    # Option 2: Using stop/count logic (thanks to @don'ttalkjustcode for pointing this out!)
    # z = [s[stop-count:stop] for stop, count in zip(accumulate(t), t)]

    print(z)

输出

[['Y', 'U'], ['U', 'N', 'U', 'U'], ['N', 'N', 'N']]
[['Y', 'U', 'U', 'N', 'U'], ['U', 'N'], ['N', 'N']]
[['Y'], ['U', 'U'], ['N', 'U', 'U', 'N', 'N', 'N']]
[['Y', 'U', 'U', 'N', 'U', 'U'], ['N'], ['N', 'N']]
[['Y', 'U'], ['U'], ['N', 'U', 'U', 'N'], ['N', 'N']]
[['Y', 'U'], ['U'], ['N', 'U'], ['U', 'N'], ['N'], ['N']]

【讨论】:

  • 巧妙使用accumulate
  • stop version 对我来说看起来更好,不需要添加 [0] 并使用最后一个总和。还有@blogon
  • 是的,但最佳答案绝对是最优雅的。它基本上是我的答案的功能版本,使用 iter(s) 而不是 while 循环。至少在我看来,使用可迭代是最直观的解决方案。
  • @don'ttalkjustcode 这似乎是该解决方案的一种更清洁的方法:) 我更新了答案以包括进行积累的观点。谢谢!
【解决方案3】:

您可以通过从s 的副本中迭代地分割块来实现您想要的结果:

i = 0
result = []
s_copy = s.copy()

while s_copy:
    result.append(s_copy[:t[i]])
    s_copy = s_copy[t[i]:]
    i += 1

【讨论】:

  • @ChrSld 不客气。确保接受已发布的答案之一。我建议当前投票最多的答案。 FWIW,目前在我上面投票的两种解决方案都使用标准库中的模块(这意味着您不需要安装任何东西,只需导入 Python 附带的模块)。
【解决方案4】:

基本上你可以使用:

s = ['Y', 'U', 'U', 'N', 'U', 'U', 'N', 'N', 'N']
t = [2, 4, 3]
st = []
offset = 0
for size in t:
    st.append(s[offset:size+offset])
    offset += size

print(st)

【讨论】:

  • 问题最初是关于制作集合列表。我的回答是迎合这一点。我没有注意到这个问题后来改变了,我的答案不再合适了。现在已经调整好了。
猜你喜欢
  • 2019-07-10
  • 1970-01-01
  • 2021-09-08
  • 1970-01-01
  • 2020-08-08
  • 2017-08-13
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
相关资源
最近更新 更多