A series or sequence of numbers is usually the product of a function and can either be infinite or finite.

In this kata we will only consider finite series and you are required to return a code according to the type of sequence:

|Code|Type|Example|
|-|-|-|
|`0`|`unordered`|`[3,5,8,1,14,3]`|
|`1`|`strictly increasing`|`[3,5,8,9,14,23]`|
|`2`|`not decreasing`|`[3,5,8,8,14,14]`|
|`3`|`strictly decreasing`|`[14,9,8,5,3,1]`|
|`4`|`not increasing`|`[14,14,8,8,5,3]`|
|`5`|`constant`|`[8,8,8,8,8,8]`|

You can expect all the inputs to be non-empty and completely numerical arrays/lists - no need to validate the data; do not go for sloppy code, as rather large inputs might be tested.

Try to achieve a good solution that runs in linear time; also, do it functionally, meaning you need to build a *pure* function or, in even poorer words, do NOT modify the initial input!

Difficulty: introductory

Starter code:

def sequence_classifier(arr):
	

Solutions:
def sequence_classifier(arr):
    if all(arr[i] == arr[i+1] for i in range(len(arr)-1)): return 5
    if all(arr[i] <  arr[i+1] for i in range(len(arr)-1)): return 1
    if all(arr[i] <= arr[i+1] for i in range(len(arr)-1)): return 2
    if all(arr[i] >  arr[i+1] for i in range(len(arr)-1)): return 3
    if all(arr[i] >= arr[i+1] for i in range(len(arr)-1)): return 4
    return 0

TYPE_SEQ = {(1,): 1, (0,1): 2, (-1,):3, (-1,0): 4, (0,): 5}

def sequence_classifier(arr):
    countSet = { (a<b) - (a>b) for a,b in zip(arr, arr[1:]) }
    return TYPE_SEQ.get(tuple(sorted(countSet)), 0)

def sequence_classifier(arr):
    strict, increasing, decreasing = True, False, False
    
    for i in range(1,len(arr)):
        if arr[i] == arr[i-1]:
            strict = False
        if arr[i] < arr[i-1]:
            decreasing = True
        if arr[i] > arr[i-1]:
            increasing = True
    
    return [increasing and decreasing, #unordered
        strict and increasing,         #strictly increasing
        not strict and increasing,     #not decreasing
        strict and decreasing,         #strictly decreasing
        not strict and decreasing,     #not increasing
        not increasing and not decreasing].index(True) #constant

def sequence_classifier(arr):
    unordered = True
    strictly_increasing = True
    not_decreasing = True
    strictly_decreasing = True
    not_increasing = True
    constant = True
    for i in range(1,len(arr)):
        if arr[i-1] != arr[i]:
            constant = False
        if arr[i-1] <= arr[i]:
           strictly_decreasing = False
        if arr[i-1] >= arr[i]:
            strictly_increasing = False
        if not arr[i-1] <= arr[i]:
           not_decreasing = False
        if not arr[i-1] >= arr[i]:
            not_increasing = False
    if constant:
        return 5
    if strictly_decreasing:
        return 3
    if strictly_increasing:
        return 1
    if not_increasing:
        return 4
    if not_decreasing:
        return 2
    return 0

def sequence_classifier(arr):
  f,l=0,len(arr)-1
  for i in range(0,l): f|= 1 if arr[i]<arr[i+1] else 2 if arr[i]==arr[i+1] else 4
  return [0,1,5,2,3,0,4,0][f]

from enum import IntEnum

class Classification(IntEnum):
    UNORDERED = 0
    INCREASING = 1
    NOT_DECREASING = 2
    DECREASING = 3
    NOT_INCREASING = 4
    CONSTANT = 5

def sequence_classifier(arr):
    unordered = True
    increasing = True
    not_decreasing = True
    decreasing = True
    not_increasing = True
    constant = True
    
    previous_val = None
    
    for val in arr:
        if previous_val is None:
            previous_val = val
            continue
            
        if increasing and val <= previous_val:
            increasing = False
        
        if not_decreasing and val < previous_val:
            not_decreasing = False
        
        if decreasing and val >= previous_val:
            decreasing = False
            
        if not_increasing and val > previous_val:
            not_increasing = False
            
        if constant and val != previous_val:
            constant = False
        
        if not unordered and not increasing and not not_decreasing and not decreasing and not not_increasing and not constant:
            return Classification.UNORDERED
        
        previous_val = val
    
    if constant: 
        return Classification.CONSTANT
    elif increasing: 
        return Classification.INCREASING
    elif not_decreasing: 
        return Classification.NOT_DECREASING
    elif decreasing: 
        return Classification.DECREASING
    elif not_increasing: 
        return Classification.NOT_INCREASING
    else:
        return Classification.UNORDERED


def sequence_classifier(arr):
    a, l, l_ = sorted(arr), len(arr), len(set(arr))
    return [[0,[[3,4][arr==a[::-1] and l_!=l],[1,2][arr==a and l_!=l]][arr==a]][arr in [a,a[::-1]]],5][l_==1]

from operator import *

def sequence_classifier(arr):
  for op, code in {eq: 5, gt: 1, lt: 3, ge: 2, le: 4}.items():
    if all(op(d, 0) for d in map(sub, arr[1:], arr)):
      return code
  return 0

from collections import Counter

def sequence_classifier(arr):
    # I would really prefer to define `types` as a set and be able to write 
    # `types -= {1, 3}`, but alas, sets do not preserve insertion order...
    types = Counter([5, 1, 2, 3, 4, 0])
    
    for a, b in zip(arr, arr[1:]):
        if a == b: del types[1], types[3]
        if a != b: del types[5]
        if a < b: del types[3], types[4]
        if a > b: del types[1], types[2]
    return next(iter(types))

def sequence_classifier(arr):
    if len(set(arr)) == 1: return 5
    elif sorted(arr) == arr and len(arr) == len(set(arr)): return 1
    elif sorted(arr) == arr: return 2
    elif sorted(arr[::-1]) == arr[::-1] and len(arr) == len(set(arr)): return 3
    elif sorted(arr[::-1]) == arr[::-1]: return 4
    else: return 0