在列表中查找单调序列?

时间:2013-06-08 14:06:37

标签: python for-loop iteration

我是Python的新手,但基本上我想用列表从列表中创建元素的子组,因此我要比较第一个元素和下一个元素,以确定我是否可以创建这些子列表,否则我将打破内部循环,我想继续最后一个元素,但在主循环中:

示例:5,7,8,4,11

比较5和7,是次要的?是的所以包括在新列表中并且内部继续下一个8,是否小于5?是的,所以包括在新列表中,但是当与4比较时,我打破了循环,所以我想继续在m中使用这4个从下一个开始,在这种情况下用11 ...

for m in xrange(len(path)):
    for i in xrange(m+1,len(path)):
              if (path[i] > path[m]):
                  newlist.append(path[i])

             else:
                  break

             m=m+i

感谢您提出建议或其他想法!

P.S。 一些输入将是: 输入:[45,78,120,47,58,50,32,34] 输出:[45,78,120],[47,58],50,[32,34]

为什么我想要制作一个双循环,因为要比较完整列表的子组,换句话说是45是小于下一个只是添加在新列表中,如果没有采取下一个比较in这个案子将是47并开始与58进行比较。

4 个答案:

答案 0 :(得分:5)

没有循环! 至少,没有显式循环......

import itertools

def process(lst):
    # Guard clause against empty lists
    if len(lst) < 1:
        return lst

    # use a dictionary here to work around closure limitations
    state = { 'prev': lst[0], 'n': 0 }

    def grouper(x):
        if x < state['prev']:
            state['n'] += 1

        state['prev'] = x
        return state['n']

    return [ list(g) for k, g in itertools.groupby(lst, grouper) ]

用法(适用于Python 2和Python 3):

>>> data = [45,78,120,47,58,50,32,34]
>>> print (list(process(data)))
[[45, 78, 120], [47, 58], [50], [32, 34]]

开玩笑,如果你需要分组列表itertools.groupby中的项目值得一点关注。并不总是最简单/最好的答案 - 但值得一试......


编辑:如果您不喜欢闭包 - 并且更喜欢使用对象来保存状态,则可以选择以下方法:

class process:
    def __call__(self, lst):
        if len(lst) < 1:
            return lst

        self.prev = lst[0]
        self.n = 0

        return [ list(g) for k, g in itertools.groupby(lst, self._grouper) ]

    def _grouper(self, x):
        if x < self.prev:
            self.n += 1

        self.prev = x
        return self.n



data = [45,78,120,47,58,50,32,34]
print (list(process()(data)))

EDIT2:因为我更喜欢闭包......但是@torek不喜欢词典语法,这里是围绕同一解决方案的第三种变体:

import itertools

def process(lst):
    # Guard clause against empty lists
    if len(lst) < 1:
        return lst

    # use an object here to work around closure limitations
    state = type('State', (object,), dict(prev=lst[0], n=0))

    def grouper(x):
        if x < state.prev:
            state.n += 1

        state.prev = x
        return state.n

    return [ list(g) for k, g in itertools.groupby(lst, grouper) ]

data = [45,78,120,47,58,50,32,34]
print (list(process(data)))

答案 1 :(得分:0)

我也使用了双循环,但将内循环放在函数中:

#!/usr/bin/env python

def process(lst):

    def prefix(lst):
        pre = []
        while lst and (not pre or pre[-1] <= lst[0]):
            pre.append(lst[0])
            lst = lst[1:]
        return pre, lst

    res=[]
    while lst:
        subres, lst = prefix(lst)
        res.append(subres) 
    return res

print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], [50], [32, 34]]

前缀函数基本上将列表拆分为2;第一部分由第一个升序数字组成,第二部分是仍然需要处理的其余部分(如果我们完成,则为空列表)。

然后,main函数简单地组装结果列表中的第一部分,然后将其余部分交给内部函数。

我不确定单值50;在你的例子中,它不在子列表中,但在我的例子中。如果是要求,则更改

        res.append(subres) 

        res.append(subres[0] if len(subres)==1 else subres)

print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], 50, [32, 34]]

答案 2 :(得分:0)

@ uselpa的版本没问题。这是我的(与[50]相同而不仅仅是50)使用collections.deque更高效,还有一些长篇评论......

#! /usr/bin/env python

from collections import deque

def process(lst):
    """
    Given a list of values that is not sorted (such that for some
    valid indices i,j, i<j, sometimes lst[i] > lst[j]), produce a
    new list-of-lists, such that in the new list, each sublist *is*
    sorted:
        for all sublist \elem returnval:
            assert_is_sorted(sublist)
    and furthermore this is the minimal set of sublists required
    to achieve the condition.

    Thus, if the input list lst is actually sorted, this returns
    [list(lst)].
    """
    def sublist(deq):
        """
        Pop items off the front of deque deq until the next one
        goes backwards.  Return the constructed sub-list.
        """
        sub = [deq.popleft()]
        while deq and deq[0] >= sub[-1]:
            sub.append(deq.popleft())
        return sub

    # Make a copy of lst before modifying it; use a deque so that
    # we can pull entries off it cheaply.
    deq = deque(lst)
    output = []
    ret = []
    while deq:
        ret.append(sublist(deq))
    return ret

print process([45,78,120,47,58,50,32,34])

(顺便提一下,在collections.deque之前的几天,我可能只使用lst的反向副本并在lst.pop()中使用sublist。这不是那么明显,虽然。)

答案 3 :(得分:-1)

为什么不简单地使用单个for循环,而不是使用itertool和所有奇特的东西。

def list_test(inlist, outlist):
    if not inlist:
        return []
    prev=inlist[0]
    x=[]
    for item in inlist:
        if item >= prev:
            x.append(item)
        else:
            outlist.append(x)
            x=[]
            x.append(item)
        prev=item
    if x:
        outlist.append(x)


in_list=[1,0,1,2,3]
out_list = []
list_test(in_list, out_list)    
print(out_list)

O / p:[[1],[0,1,2,3]]