【问题标题】:How do you split a list into monotonically increasing/decreasing lists?如何将列表拆分为单调递增/递减的列表?
【发布时间】:2021-09-22 19:32:38
【问题描述】:

我有一个包含几个单调递减元素的 python 列表。然而,所有这些序列并不相邻 A = [[100, 83, 82, 51, 45, 29, 100, 100, 88, 88, 76, 76, 76, 59, 10, 12, 36, 100, 100, 86, 81, 79, 65, 65, 9, 10, 8]

我想从A 中提取a1 = [100, 83, 82, 51, 45, 29]a2=[100, 100, 88, 88, 76, 76, 76, 59, 10]a3=[100, 100, 86, 81, 79, 65, 65, 9]。正如您必须注意到的,我从A 中丢弃了12,36,10,8,因为它们不遵循任何模式。每个子数组的第一个元素应该大于 80。因此,我丢弃了以 10 作为初始元素的单调子数组 到目前为止,我有这个。

def chop_array(array):
    itr = 0
    prev_element = 1e6
    window = list()
    mainWindow = list ()
    for i, element in enumerate(array):
        if element <= prev_element:
            window.append(element)
            prev_element = element
        else:
            mainWindow.append(window)
            prev_element = element
            window = list()
            window.append(element)
    filter_array = [True if item[0] > 80  else False for  item in mainWindow]
    return list(itertools.compress(mainWindow,filter_array))

在 python 中有没有更有效的方法?

【问题讨论】:

  • 100,100 并不是严格递减的。
  • 感谢更正
  • 你能解释一下为什么列表末尾的[10, 8] 被丢弃了吗?它形成一个单调递减的子列表。
  • @MustafaAydın 我已经编辑了描述,每个子阵列可以有多小有一个阈值要求。现在让我们假设每个子数组应该有 80 作为第一个元素

标签: python python-3.x list numpy


【解决方案1】:

可以通过查看与前一个差异为正的位置来检测每个子列表的起始条目。然后我们可以在这些位置上拆分数组;但是由于np.diff 将数组大小缩小了 1,因此我们将输出加 1 以获得相对于原始数组的索引:

>>> sub_lists = np.split(A, np.where(np.diff(A) > 0)[0] + 1)
>>> sub_lists

[array([100,  83,  82,  51,  45,  29]),
 array([100, 100,  88,  88,  76,  76,  76,  59,  10]),
 array([12]),
 array([36]),
 array([100, 100,  86,  81,  79,  65,  65,   9]),
 array([10,  8])]

需要对这个数组列表进行两种过滤:第一种是丢弃任何包含 1 项的列表,第二种是丢弃第一个条目小于 80 的列表。因此,

>>> result = [sub for sub in sub_lists if sub.size > 1 and sub[0] > 80]
>>> result

[array([100,  83,  82,  51,  45,  29]),
 array([100, 100,  88,  88,  76,  76,  76,  59,  10]),
 array([100, 100,  86,  81,  79,  65,  65,   9])]

我们可以将它们包装在一个函数中:

def split_decreasing(arr, thre=80):
    """
    Splits the given array `arr` into monotonically decreasing subarrays
    of size at least 2 and first entries being at least `thre`.
    """
    split_points = np.where(np.diff(arr) > 0)[0] + 1
    sub_lists = np.split(arr, split_points)
    result = [sub for sub in sub_lists if sub.size > 1 and sub[0] > thre]
    return result

示例运行:

>>> split_decreasing([63, 44, 43, 37, 30, 30, 27, 95, 91, 70, 65, 62, 62, 56, 56])

[array([95, 91, 70, 65, 62, 62, 56, 56])]

>>> split_decreasing(np.arange(10))
[]

>>> split_decreasing([12, 11, 7, 9, 7], thre=80)
[]

>>> split_decreasing([12, 11, 7, 9, 7], thre=10)
[array([12, 11,  7])]

>>> split_decreasing([12, 11, 7, 9, 7], thre=5)
[array([12, 11,  7]), array([9, 7])]

>>> split_decreasing([100, 83, 82, 51, 45, 29, 100, 100, 88, 88, 76, 76, 76,
                      59, 10, 12, 36, 100, 100, 86, 81, 79, 65, 65, 9, 10, 8])

[array([100,  83,  82,  51,  45,  29]),
 array([100, 100,  88,  88,  76,  76,  76,  59,  10]),
 array([100, 100,  86,  81,  79,  65,  65,   9])]

【讨论】:

  • @Mustafa Aydin 我注意到您的方法不适用于看起来像[63, 44, 43, 37, 30, 30, 27, 95, 91, 70, 65, 62, 62, 56, 56] 的列表。因此,我不得不拒绝它作为答案。函数应该返回 [95, 91, 70, 65, 62, 62, 56, 56],但是,您的方法返回一个空列表
  • 嗨@Spandyie,我尝试使用该示例,但它确实按预期返回了一个元素列表[array([95, 91, 70, 65, 62, 62, 56, 56])]。 (抱歉回复晚了;时区差异...)
  • (我将操作包装在一个函数中并放置了一些示例运行)
  • @MustafaAydın 谢谢!
【解决方案2】:

有一种方法可以通过将其视为队列来解决此问题,因为根据索引的下一条记录本质上是我们想要与其他记录进行比较的内容。这种方法的额外好处是您正在删除记录并重新分配它。因此,您不会将这里的内存增加一倍。

我要提到的一件事是,使用列表来存储结果列表将是一种快速保存进度的解决方案。

A = [100, 83, 82, 51, 45, 29, 100, 100, 88, 88, 76, 76, 76, 59, 10, 12, 36, 100, 100, 86, 81, 79, 65, 65, 9, 10, 8]

result = [] # list of lists
r = [] # initialize the logic
r.append(A.pop(0))
while len(A) > 0:
    try:
        # pop the next value
        v = A.pop(0)

        # if its the first value of a sublist, or if its less than the previous record but greater than the next:
        # then add it to the sublist
        if r == [] or (r[-1] >= v and v >= A[0]):
            r.append(v)
        else:
            r.append(v)
            if len(r) > 2:
                result.append(r)
            r = [] # reset the list
    
    # end of the big list, no A[1] to find
    except IndexError as e:
        # add the last one to the r list
        if r[-1] >= v:
            r.append(v)
            if len(r) > 2:
                result.append(r)
        print('reached End of List')
print(result)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多