【问题标题】:List divide based on element from another list根据另一个列表中的元素进行列表划分
【发布时间】:2021-12-15 13:40:56
【问题描述】:

我有两个列表如下

a = [646, 650, 654, 658, 662, 666, 670, 674, 678, 682, 686, 690, 694, 698, 702, 706, 13565, 13569, 13573, 13577, 13581, 13585, 13589, 13593, 13597, 13601, 13605, 13609, 13613, 13617, 13621, 13625, 13629, 13633, 13637, 13641, 13645, 13649, 13653, 13657, 13661, 21237, 21241, 21245, 21249, 21253, 21257, 21261, 21265, 21269, 21273, 21277, 21281, 21285, 21289, 21293, 21297, 21301, 21305, 21309, 21313, 21317, 21321, 21325, 21329, 21333, 21337, 21341, 21345]

b = [646, 706, 13661, 21345]

所以基本上我想根据列表b 中的开始停止值将列表a 分成更小的块。例如。 像这样的

[
[646, 650, 654, 658, 662, 666, 670, 674, 678, 682, 686, 690, 694, 698, 702, 706],
[13565, 13569, 13573, 13577, 13581, 13585, 13589, 13593, 13597, 13601, 13605, 13609, 13613, 13617, 13621, 13625, 13629, 13633, 13637, 13641, 13645, 13649, 13653, 13657, 13661],
[21237, 21241, 21245, 21249, 21253, 21257, 21261, 21265, 21269, 21273, 21277, 21281, 21285, 21289, 21293, 21297, 21301, 21305, 21309, 21313, 21317, 21321, 21325, 21329, 21333, 21337, 21341, 21345]
]

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 如果在 list a 中没有找到 list b 中的“stop”值,您希望发生什么?另外,两个列表中的值是否按升序排序?

标签: python python-3.x list


【解决方案1】:

解决方案 1:使用二分法

我将通过使用bisect 模块来查找a 中的每个项目将在b 中插入的位置来确定项目属于哪个bin 来解决这个问题。

此解决方案不需要对a 进行排序,但它确实要求对b 进行排序。

bin_boundaries = sorted(b)
results = [[] for _ in range(len(bin_boundaries)+1)]
for i in a:
    pos = bisect.bisect_left(bin_boundaries, i)
    results[pos].append(i)
print(results)

现在,您没有指定是否需要与上一个或下一个 bin 中的边界相等的项目。我把它放在以前的箱子里。如果您指的是下一个,请将上面的 bisect_left 替换为 bisect_right

我还输出了您预期的输出显示的另外两个 bin:第一个 bin 的项目小于第一个 bin 边界,最后一个 bin 项目大于最后一个边界。如果您想删除这些边缘箱,请添加 results = results[1:-1]

解决方案 2:只需遍历每个 bin 的列表

现在,这是一个更简单的解决方案,它只为每个 bin 遍历 a

bin_boundaries = sorted(b)
results = []
for low, high in zip(bin_boundaries[:-1], bin_boundaries[1:]):
    results.append([i for i in a if i > low and i <= high])
print(results)

这一次,我没有创建边缘箱。同样,修复 &gt;&lt;= 以匹配您在边缘处实际需要的语义。

这个外层循环也可以变成一个列表推导,给你这个嵌套列表推导和一个非常紧凑的解决方案:

results = [
    [i for i in a if i > low and i <= high]
    for low, high in zip(bin_boundaries[:-1], bin_boundaries[1:])
]

【讨论】:

  • 谢谢...这解决了我的问题。只是一个小问题......为什么 646 在解决方案一中作为独立列表出现,或者它根本不包含在其余列表解决方案中? @joanis
  • @MeghaSirisilla 那是因为您没有指定如何处理等于边界的数字:使用b=[646, 706...],646 是属于第一个 bin 还是在第一个 bin 之前? 706 属于第一个 bin 还是第二个 bin?在您的预期输出中,您给出的答案不一致:646 在第一个 bin 之前,706 在第一个 bin 中,或者 646 在第一个 bin 中,706 在第二个 bin 中。告诉我你想要哪个,我可以确定答案。或者根据您对该问题的回答,按照我在解决方案中的建议调整我的代码。
  • 在我的预期输出中,我也从 646 开始了我的第一个 bin,并以 706 结束。两者都是第一个 bin 的第一个和最后一个元素。这就是我想要的。 646 是第一个 bin 的开始,706 是结束。如果您可以编辑您的答案,我将不胜感激。谢谢。
【解决方案2】:

从您的示例中,我了解到您希望第一个区间包含边界 ([646, 706]),而其他区间必须仅包含上边界 (]706, 13661], ]13661, 21345)。

我在这里使用 .index 方法和一个考虑第一个区间的下边界并为其他区间排除它的 for 循环:

lists_result = []

for i in range(len(b[:-1])):
    idx_inf = a.index(b[i])
    idx_sup = a.index(b[i+1])
    if i == 0:
        lists_result.append(a[idx_inf:idx_sup+1])
    else:
        lists_result.append(a[idx_inf+1:idx_sup+1])

【讨论】:

  • 此解决方案正确提供所有列表。谢谢你,@CorradoB
  • @MeghaSirisilla 此解决方案依赖于b 的元素出现在a 中这一事实,如果该假设成立,则效果很好。这真的是你的意图吗?
  • 是的...... b 的所有元素将始终存在于 a 中。它永远不会不同。
猜你喜欢
  • 2023-02-23
  • 2018-07-14
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多