Python 如何根据相邻阵列之间的给定准则将一个阵列拆分为几个较小的阵列

Python 如何根据相邻阵列之间的给定准则将一个阵列拆分为几个较小的阵列,python,arrays,split,wolfram-mathematica,Python,Arrays,Split,Wolfram Mathematica,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>%timeit按([2,3,5

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)和]给出:

而SplitBy[a,(Mod[#,2]==0)&]给出:

实际上,要拆分的数组可能是一个二维表,测试函数可能会处理各个列中的元素


如何在Python3中有效地编码这种行为

您的问题的第一部分没有快速的答案,lenik已经提供了一个很好的基于
zip
的解决方案,但是
SplitBy
可以使用
itertools
模块()的
groupby
功能轻松复制

注意,
groupby
将在每次更改密钥时插入分隔符(~创建新组)。因此,如果您想要类似于拆分的
,则必须首先根据键函数对其进行排序

最后,它会给你这样的东西:

>>> 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_u,g在其中。groupby(sorted(l,key=func,key=func)]

Quick timeit在我破旧的笔记本电脑上的基准测试:

  • itertools版本
>>%timeit按([2,3,5,7,11,13,17,19,23,29],λx:x%2)拆分
每个回路8.42µs±92.8 ns(7次运行的平均值±标准偏差,每个100000个回路)

  • 压缩版本
>>%timeit按([2,3,5,7,11,13,17,19,23,29],λx:x%2)拆分
每个回路10.8µs±53.7 ns(7次运行的平均值±标准偏差,每个100000个回路)

  • try/catch版本
>>%timeit按([2,3,5,7,11,13,17,19,23,29],λx:x%2)拆分

每个回路12.6µs±162 ns(7次运行的平均值±标准偏差,每个100000个回路)

以下是一些可能的解决方案:

a) 使用python内置zip

def split(lst, test):
    res = []
    sublst = []

    for x, y in zip(lst, lst[1:]):
        sublst.append(x)
        if not test(x, y):
            res.append(sublst)
            sublst = []

    if len(lst) > 1:
        sublst.append(lst[-1])
        if not test(lst[-2], lst[-1]):
            res.append(sublst)
            sublst = []

    if sublst:
        res.append(sublst)

    return res


def split_by(lst, test):
    return split(lst, lambda x, y: test(x) == test(y))


if __name__ == '__main__':
    a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    print(split(a, lambda x, y: y - x < 4))
    print(split_by(a, lambda x: (x % 2) == 0))

如果反对者至少能给出反馈或解释我错的原因,我会很高兴改进这个答案。我对你的答案投了赞成票,但让我澄清一下原因,我不认为答案错了,但有点短,如果你将自己的方式包装成几个函数split/split_by,并发布了一个应用于建议op示例的简短片段,这将足以在第一时间对你的答案进行投票。仅供参考,我不喜欢投否决票,但在这种情况下,我认为这篇文章很有趣,这些快速的回答并没有公平地回答原来的问题:)@BPL谢谢你的反馈,我刚刚更新了我的答案;)好的,那么+1;)。对不起,当我投了反对票时,我应该在没有你要求的情况下立即提供反馈。事实上,我总是鼓励那些为了改进我的答案而否决我答案的人这样做。谢谢。有趣的统计数据,谢谢发布。事实上,当我昨天发布我的答案时,我想检查一下这一点,如果内部try/catch的开销太大了,是的,看起来确实如此。输出中缺少
29
。如果你复制粘贴我的代码,至少不要遗漏重要部分…@lenik编辑了我的答案,但请向我澄清一点,事实上我考虑使用你删除的答案中的内置python zip,这足以让我对复制粘贴你的代码的评论进行否决?我之前的回答在结构上与你的不同,所以对我来说,这更像是一个简单的幼稚的否决票。我可能错了,和平:)
>>> 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]]
def split(lst, test):
    res = []
    sublst = []

    for x, y in zip(lst, lst[1:]):
        sublst.append(x)
        if not test(x, y):
            res.append(sublst)
            sublst = []

    if len(lst) > 1:
        sublst.append(lst[-1])
        if not test(lst[-2], lst[-1]):
            res.append(sublst)
            sublst = []

    if sublst:
        res.append(sublst)

    return res


def split_by(lst, test):
    return split(lst, lambda x, y: test(x) == test(y))


if __name__ == '__main__':
    a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    print(split(a, lambda x, y: y - x < 4))
    print(split_by(a, lambda x: (x % 2) == 0))
def split(lst, test):
    res = []
    sublst = []

    for i, x in enumerate(lst):
        try:
            y = lst[i + 1]
            sublst.append(x)
        except IndexError:
            x, y = lst[i - 1], lst[i]
            sublst.append(y)

        if not test(x, y):
            res.append(sublst)
            sublst = []

    if sublst:
        res.append(sublst)

    return res


def split_by(lst, test):
    return split(lst, lambda x, y: test(x) == test(y))


if __name__ == '__main__':
    a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    print(split(a, lambda x, y: y - x < 4))
    print(split_by(a, lambda x: (x % 2) == 0))
[[2, 3, 5, 7], [11, 13], [17, 19], [23], [29]]
[[2], [3, 5, 7, 11, 13, 17, 19, 23, 29]]