Mathematica 有两个非常有用的函数,可以根据给定的条件将数组分组为较小数组的列表:Split[] 和 SplitBy[],我需要在 Python3 代码中模拟它们:
Split[list,test] 将成对的相邻元素视为相同,只要将函数 “test” 应用于它们会产生 True,
SplitBy[list,f] 将列表拆分为子列表,这些子列表由一系列连续元素组成,这些元素在应用 f 时给出相同的值。
因此如果
a=[2,3,5,7,11,13,17,19,23,29]
拆分[a,(#2-#1 < 4)&] 给出:
[[2,3,5,7],[11,13],[17,19],[23],[29]]
和 SplitBy[a,(Mod[#,2]==0)&] 给出:
[[2],[3,5,7,11,13,17,19,23,29]]
在实践中,要拆分的数组可能是一个二维表,测试函数可能会作用于各个列中的元素。
如何在 Python3 中高效地编码这种行为?
最佳答案
对于问题的第一部分没有快速的答案,lenik 已经提供了一个很好的基于 zip
的解决方案,但是 SplitBy
可以很容易地使用itertools
模块 ( doc here ) 的 groupby
函数。
请注意,groupby
会在每次更改键值时插入一个分隔符(~ 创建一个新组)。所以如果你想要像SplitBy
这样的东西,你必须先根据键函数对它进行排序。
最后,它会给你这样的东西:
>>> def split_by(l, func):
groups = []
sorted_l = sorted(l, key=func)
for _, g in it.groupby(sorted_l, key=func):
groups.append(list(g))
return groups
>>> split_by([2,3,5,7,11,13,17,19,23,29], lambda x: x%2)
[[2], [3, 5, 7, 11, 13, 17, 19, 23, 29]]
使用列表理解的单行版本:
splited_by = [list(g) for _, g in it.groupby(sorted(l, key=func), key=func)]
在我破旧的笔记本电脑上进行 Quick timeit 基准测试:
- itertools 版本
>>> %timeit split_by([2,3,5,7,11,13,17,19,23,29], lambda x: x%2)
每个循环 8.42 µs ± 92.8 ns(7 次运行的平均值 ± 标准偏差,每次 100000 次循环)
- 压缩版
>>> %timeit split_by([2,3,5,7,11,13,17,19,23,29], lambda x: x%2)
每个循环 10.8 µs ± 53.7 ns(7 次运行的平均值 ± 标准偏差,每次 100000 次循环)
- 尝试/捕捉版本
>>> %timeit split_by([2,3,5,7,11,13,17,19,23,29], lambda x: x%2)
每个循环 12.6 µs ± 162 ns(7 次运行的平均值 ± 标准偏差,每次 100000 次循环)
关于python - 如何根据邻居之间的给定标准将数组拆分为几个较小的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58537770/