【问题标题】:Python: Split list in subsets if the current element is minor than previous elementPython:如果当前元素小于前一个元素,则在子集中拆分列表
【发布时间】:2015-09-09 05:07:57
【问题描述】:

我有以下 python 列表:

my_list = [1, 2, 3, 1, 2, 1, 2, 3]

我正在寻找一种有效的方法,仅当当前元素小于前一个元素时,才将列表拆分为多个子列表。

在示例中,我应该得到:

result = [[1,2,3],[1,2],[1,2,3]]

我应该得到三个子集,因为 1

我只得到了这个解决方案的第一个元素:

[[x] for index, x in enumerate(my_list) if index < 1 or x < my_list[index - 1]]

结果:

[[1], [1], [1]]

再次尝试,结果相同:

[ [my_list[x]] for x in range(len(my_list)) if my_list[x] < my_list[x-1]]

【问题讨论】:

  • 结果是因为您仅在满足条件时才输入值,即在您的情况下为 1 时
  • 谢谢,我似乎只获取了其他回复中看到的断点

标签: python algorithm list list-comprehension subset


【解决方案1】:

这是一种易于理解的方法。但是,虽然你可以把它塞进一个长长的表达中,但你到底为什么要这么做?

>>> my_list = [1, 2, 3, 1, 2, 1, 2, 3]
>>> brks = [i for i in range(1,len(my_list)) if my_list[i] < my_list[i-1]]
>>> [my_list[x:y] for x,y in zip([0]+brks,brks+[None])]
[[1, 2, 3], [1, 2], [1, 2, 3]]

这只需找到一个新组的开始点并使用这些点切入my_list

【讨论】:

  • 嗯,以理解的方式思考并不是解决这个问题的最佳焦点,但我想知道我是否可以用它来实现一些目标。将您的答案标记为更接近我的解决方案,但其他解决方案也确实适用于我
【解决方案2】:

我认为您不能使用简单的列表推导来做到这一点。一个简单的方法是普通的 for 循环方法 -

new_list = []
prev = float('inf')
for x in my_list:
    if x < prev:
        temp = []
        new_list.append(temp)
    temp.append(x)
    prev = x

演示 -

>>> my_list = [1, 2, 3, 1, 2, 1, 2, 3]
>>> new_list = []
>>> prev = float('inf')
>>> for x in my_list:
...     if x < prev:
...         temp = []
...         new_list.append(temp)
...     temp.append(x)
...     prev = x
...
>>> new_list
[[1, 2, 3], [1, 2], [1, 2, 3]]

这里给出的不同方法的时序比较-

代码-

from itertools import groupby

def func1(my_list):
    new_list = []
    prev = float('inf')
    for x in my_list:
        if x < prev:
            temp = []
            new_list.append(temp)
        temp.append(x)
        prev = x
    return new_list


def func2(my_list):
    brks = [i for i in range(1,len(my_list)) if my_list[i] < my_list[i-1]]
    return [my_list[x:y] for x,y in zip([0]+brks,brks+[None])]

def func3(my_list):
    return [list(next(g)) + [x[1] for x in g] for k, g in 
                  groupby(zip(my_list, my_list[1:]), lambda x: x[1] >= x[0]) if k]

def func4(my_list):
    results = []
    for i, x in enumerate(my_list):
        if i == 0:
            results.append([x])
            continue
        if x < my_list[i - 1]:
            results.append([x])
        else:
            results[-1].append(x)
    return results

import random
my_list = [random.randint(1,10) for _ in range(1000)]

结果 -

In [20]: %timeit func1(my_list)      #Simple for-loop
1000 loops, best of 3: 236 µs per loop

In [21]: %timeit func2(my_list)      #List comprehension using breaks.
1000 loops, best of 3: 293 µs per loop

In [22]: %timeit func3(my_list)      #@Ashwini's One-liner
1000 loops, best of 3: 689 µs per loop

In [23]: %timeit func4(my_list)      #@electrometro's approach.
1000 loops, best of 3: 407 µs per loop

In [31]: %timeit func1(my_list)
1000 loops, best of 3: 223 µs per loop

In [32]: %timeit func2(my_list)
1000 loops, best of 3: 293 µs per loop

In [33]: %timeit func3(my_list)
1000 loops, best of 3: 703 µs per loop

In [34]: %timeit func4(my_list)
1000 loops, best of 3: 415 µs per loop

【讨论】:

  • 有趣的方法。
  • 这是我第一次关注这一点,但我试图避免正常的循环/条件并为此存储。
  • 正常循环/条件有什么问题?
  • 在正常循环/条件下没有问题,只是尝试使用 python 技能,据我所知,这是更有效的时间花费方式
【解决方案3】:

这是一个可行的解决方案。如果您愿意,可以将其转换为列表推导式,但它会相当难看。

my_list = [1, 2, 3, 1, 2, 1, 2, 3]

results = []
for i, x in enumerate(my_list):
    if i == 0:
        results.append([x])
        continue
    if x < my_list[i - 1]:
        results.append([x])
    else:
        results[-1].append(x)

print results

【讨论】:

    【解决方案4】:

    你也可以使用 numpy:

    import numpy as np
    
    my_list = np.array([1, 2, 3, 1, 2, 1, 2, 3])
    
    print(np.split(my_list, np.where(np.diff(my_list) < 0)[0] + 1))
    [array([1, 2, 3]), array([1, 2]), array([1, 2, 3])]
    

    【讨论】:

      猜你喜欢
      • 2016-04-29
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      • 2022-12-05
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多