【问题标题】:Count monotonic items in a python list [closed]计算python列表中的单调项[关闭]
【发布时间】:2019-02-10 12:34:58
【问题描述】:

假设我有以下列表x = [1,2,3,3,2,0],我想计算单调项的数量(增加、减少和恒定)。所以,在我的例子中:

1. Increasing: [1,2], [2,3], [1,2,3]
2. Constant: [3,3]
3. Decreasing: [3,2], [2,0], [3,2,0]

共 7 项。

提前谢谢你。

【问题讨论】:

  • 到目前为止你尝试过什么?
  • 1.我看到了这个答案,它检查了一个完整的列表:stackoverflow.com/questions/4983258/…。还有这个:stackoverflow.com/questions/17000300/…(这与我要找的很接近).. 但我不确定如何将其扩展到我的需要
  • 扫描列表以跟踪先前的元素并附加到您的增加/相同/减少列表,然后获取这些列表的所有子段。
  • @tobias_k “跟踪以前的元素”是什么意思?我可以寻找像state['prev'] 这样的东西,它允许我检查元素对之间的关​​系,但是如果我有一个看起来像 [1,2,3,4] 的子列表,我需要在其中创建这一项中有 6 项 ([1,2], [2,3], [3,4], [1,2,3], [2,3,4], [1,2,3,4].

标签: python


【解决方案1】:

由于您没有显示任何代码,我只是给您一些提示。主要思想是逐步检查您的序列,从第二个项目(索引1)开始,并更新每个项目的信息,计算以该项目结束的单调序列的数量。

在您逐步​​浏览列表时存储几条信息。首先,您需要一个计数器来处理三种单调序列。无需单独计算序列的种类:您可以在一个计数器中将它们一起计算。您需要一个三向或四向信号来记录前​​一个单调序列的序列类型(递增、恒定或递减),并且您需要一个整数来显示前一个单调序列的长度。使用该信息,您可以使用适当的数量更新适当的计数器。请注意,在处理任何类型的单调序列之前,您需要小心处理列表的开头。

现在逐步浏览您的输入列表,从第二项(索引1)开始。将当前项目与前一个项目进行比较。更新当前单调序列的长度:如果最后两项的方向与之前的方向一致,那么你的单调序列就变大了一项;否则,你有一个长度最小的新单调序列。现在用新的单调序列的数量增加你的总计数器。如果您的新序列的长度为 2(先前和当前项目),则添加 1,如果新序列的长度为 3,则添加 2,依此类推。

处理这些提示。如果您需要更多帮助,请展示更多您的工作并解释您遇到的问题,然后寻求更多帮助。但是你需要表现出更多你自己的努力。我已经编写了遵循这些提示的代码,它很好、高效且简短。编码愉快!


在另一个回答者的基础上,他认为你已经展示了足够的工作,这是我的代码。 (为了完整起见,我展示了这段代码——请不要从另一个答案中删除你的“接受”。)我包括两个可以很容易地插入到主例程中的小函数,但它们本身就是有用的函数。

def pairwise(seq):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    if seq:
        return zip(seq, seq[1:])
    else:
        return zip()

def cmp(x, y):
    """Return an integer depending on the comparison of two values.
    Return -1 if x <  y, 
            0 if x == y,
            1 if x >  y.
    """
    return (x > y) - (y > x)  # a common Python trick: bool values to int

def count_monotonic_subsequences(seq):
    """Return the number of monotonic (consecutive) subsequences of
    length at least 2 in a sequence."""
    run_length = 0
    prev_cmp = None  # no comparisons done yet
    count_so_far = 0
    # For each item, add how many monotonic sequences end with that item
    for prev_item, item in pairwise(seq):
        this_cmp = cmp(prev_item, item)
        if this_cmp == prev_cmp:
            run_length += 1  # this item extends the previous mono subsequence
        else:
            run_length = 1  # this item begins a new monotonic subsequence
        prev_cmp = this_cmp
        count_so_far += run_length  # add new mono subsequences ending here
    return count_so_far

print(count_monotonic_subsequences([1,2,3,3,2,0])) # 7

【讨论】:

    【解决方案2】:

    通过将其分解为更小的步骤来解决此问题要容易得多。首先,通过跟踪以前的值和当前值,按趋势(增加、相等或减少)对项目进行分组。
    收集所有结果,然后根据需要将结果分解为更小的列表,以便在第二步中获得所需的输出。

    我鼓励您按照代码中的 cmets 进行操作,并尝试自己实施这些步骤。

    x = [1,2,3,3,2,0]
    prev = x[0] 
    curr = x[1] #keep track of two items together during iteration, previous and current
    result = {"increasing": [],
              "equal": [],
              "decreasing": [],
              }
    
    
    def two_item_relation(prev, curr): #compare two items in list, results in what is effectively a 3 way flag
        if prev < curr:
            return "increasing"
        elif prev == curr:
            return "equal"
        else:
            return "decreasing"
    
    
    prev_state = two_item_relation(prev, curr) #keep track of previous state
    result[prev_state].append([prev]) #handle first item of list
    
    x_shifted = iter(x)
    next(x_shifted) #x_shifted is now similar to x[1:]
    
    for curr in x_shifted: 
        curr_state = two_item_relation(prev, curr)
        if prev_state == curr_state: #compare if current and previous states were same.
            result[curr_state][-1].append(curr) 
        else: #states were different. aka a change in trend
            result[curr_state].append([])
            result[curr_state][-1].extend([prev, curr])
        prev = curr
        prev_state = curr_state
    
    def all_subcombinations(lst): #given a list, get all "sublists" using sliding windows
        if len(lst) < 3:
            return [lst]
        else:
            result = []
        for i in range(2, len(lst) + 1):
            for j in range(len(lst) - i + 1):
                result.extend([lst[j:j + i]])
        return result
    
    
    
    print(" all Outputs ")
    result_all_combinations = {}
    
    for k, v in result.items():
        result_all_combinations[k] = []
        for item in v:
            result_all_combinations[k].extend(all_subcombinations(item))
    
    print(result_all_combinations)
    #Output:
    {'increasing': [[1, 2], [2, 3], [1, 2, 3]],
     'equal': [[3, 3]],
     'decreasing': [[3, 2], [2, 0], [3, 2, 0]]}
    

    【讨论】:

    • 你确定你应该为一个工作量很少的问题提供一个完整的代码解决方案吗?
    • OPs cmets 让我对努力寻找解决方案感到满意,在我看来,他们至少首先努力探索。对我来说,这比我见过的大多数人都好。
    • 既然您认为 OP 已经展示了足够的工作,为了完整起见,我将在我自己的答案中添加代码。当然,您的答案仍应作为公认的答案。
    • 看你的回答,我不同意。写的真好,谢谢补充,学习了。 +1。 @RoryDaulton
    猜你喜欢
    • 1970-01-01
    • 2018-04-02
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多