[python] Python-목록 단 조성을 확인하는 방법

목록 단 조성을 확인 하는 효율적이고 비단뱀적인 방법 은 무엇입니까 ?
즉, 단조롭게 증가하거나 감소하는 값이 있습니까?

예 :

[0, 1, 2, 3, 3, 4]   # This is a monotonically increasing list
[4.3, 4.2, 4.2, -2]  # This is a monotonically decreasing list
[2, 3, 1]            # This is neither



답변

평등이 허용되는지 여부가 명확하지 않기 때문에 “증가”또는 “감소”와 같은 모호한 용어는 피하는 것이 좋습니다. 예를 들어 항상 “비 증가”(분명히 평등이 허용됨) 또는 “엄격히 감소”(분명히 평등이 허용되지 않음) 중 하나를 사용해야합니다.

def strictly_increasing(L):
    return all(x<y for x, y in zip(L, L[1:]))

def strictly_decreasing(L):
    return all(x>y for x, y in zip(L, L[1:]))

def non_increasing(L):
    return all(x>=y for x, y in zip(L, L[1:]))

def non_decreasing(L):
    return all(x<=y for x, y in zip(L, L[1:]))

def monotonic(L):
    return non_increasing(L) or non_decreasing(L)


답변

숫자 목록이 많은 경우 numpy를 사용하는 것이 가장 좋을 수 있으며 다음과 같은 경우에는

import numpy as np

def monotonic(x):
    dx = np.diff(x)
    return np.all(dx <= 0) or np.all(dx >= 0)

트릭을해야합니다.


답변

import itertools
import operator

def monotone_increasing(lst):
    pairs = zip(lst, lst[1:])
    return all(itertools.starmap(operator.le, pairs))

def monotone_decreasing(lst):
    pairs = zip(lst, lst[1:])
    return all(itertools.starmap(operator.ge, pairs))

def monotone(lst):
    return monotone_increasing(lst) or monotone_decreasing(lst)

이 접근 방식은 O(N)목록의 길이에 있습니다.


답변

@ 6502에는 목록에 대한 완벽한 코드가 있습니다. 모든 시퀀스에서 작동하는 일반 버전을 추가하고 싶습니다.

def pairwise(seq):
    items = iter(seq)
    last = next(items)
    for item in items:
        yield last, item
        last = item

def strictly_increasing(L):
    return all(x<y for x, y in pairwise(L))

def strictly_decreasing(L):
    return all(x>y for x, y in pairwise(L))

def non_increasing(L):
    return all(x>=y for x, y in pairwise(L))

def non_decreasing(L):
    return all(x<=y for x, y in pairwise(L))


답변

팬더의 패키지이 편리합니다.

import pandas as pd

다음 명령은 정수 또는 부동 소수점 목록과 함께 작동합니다.

단조롭게 증가 (≥) :

pd.Series(mylist).is_monotonic_increasing

단조롭게 증가 (>) :

myseries = pd.Series(mylist)
myseries.is_unique and myseries.is_monotonic_increasing

문서화되지 않은 개인 방법을 사용하는 대안 :

pd.Index(mylist)._is_strictly_monotonic_increasing

단조 감소 (≤) :

pd.Series(mylist).is_monotonic_decreasing

엄격히 단조 감소 (<) :

myseries = pd.Series(mylist)
myseries.is_unique and myseries.is_monotonic_decreasing

문서화되지 않은 개인 방법을 사용하는 대안 :

pd.Index(mylist)._is_strictly_monotonic_decreasing


답변

import operator, itertools

def is_monotone(lst):
    op = operator.le            # pick 'op' based upon trend between
    if not op(lst[0], lst[-1]): # first and last element in the 'lst'
        op = operator.ge
    return all(op(x,y) for x, y in itertools.izip(lst, lst[1:]))


답변

다음은 reduce복잡성을 사용하는 기능적 솔루션 입니다 O(n).

is_increasing = lambda L: reduce(lambda a,b: b if a < b else 9999 , L)!=9999

is_decreasing = lambda L: reduce(lambda a,b: b if a > b else -9999 , L)!=-9999

9999값의 상한선과 하한선으로 바꿉니다 -9999. 예를 들어 숫자 목록을 테스트하는 경우 10및 을 사용할 수 있습니다 -1.


@ 6502의 답변 과 더 빠른 성능을 테스트했습니다 .

사례 True : [1,2,3,4,5,6,7,8,9]

# my solution .. 
$ python -m timeit "inc = lambda L: reduce(lambda a,b: b if a < b else 9999 , L)!=9999; inc([1,2,3,4,5,6,7,8,9])"
1000000 loops, best of 3: 1.9 usec per loop

# while the other solution:
$ python -m timeit "inc = lambda L: all(x<y for x, y in zip(L, L[1:]));inc([1,2,3,4,5,6,7,8,9])"
100000 loops, best of 3: 2.77 usec per loop

두 번째 요소의 경우 False :[4,2,3,4,5,6,7,8,7] :

# my solution .. 
$ python -m timeit "inc = lambda L: reduce(lambda a,b: b if a < b else 9999 , L)!=9999; inc([4,2,3,4,5,6,7,8,7])"
1000000 loops, best of 3: 1.87 usec per loop

# while the other solution:
$ python -m timeit "inc = lambda L: all(x<y for x, y in zip(L, L[1:]));inc([4,2,3,4,5,6,7,8,7])"
100000 loops, best of 3: 2.15 usec per loop