A palindrome is a word, phrase, number, or other sequence of characters which reads the same backward as forward. Examples of numerical palindromes are: 

2332
110011
54322345

For a given number ```num```, return its closest numerical palindrome which can either be smaller or larger than ```num```. If there are 2 possible values, the larger value should be returned. If ```num``` is a numerical palindrome itself, return it. 

For this kata, single digit numbers will NOT be considered numerical palindromes. 

Also, you know the drill - be sure to return "Not valid" if the input is not an integer or is less than 0.

```
palindrome(8) => 11
palindrome(281) => 282 
palindrome(1029) => 1001
palindrome(1221) => 1221
palindrome("1221") => "Not valid"

```

```Haskell
In Haskell the function should return a Maybe Int with Nothing for cases where the argument is less than zero.
```
Other Kata in this Series:
Numerical Palindrome #1
Numerical Palindrome #1.5
Numerical Palindrome #2
Numerical Palindrome #3
Numerical Palindrome #3.5
Numerical Palindrome #4
Numerical Palindrome #5

Difficulty: introductory

Starter code:

def palindrome(num):
	

Solutions:
def palindrome(num):
    if type(num) is not int or num < 0:
        return "Not valid"
    else:
        c =0
        for i in range(num,num**2):
            if is_pal(i):
                return i
            elif is_pal(i-c):
                return i-c
            else:
                c +=2
    
def is_pal(n):
    return n > 10 and n == int(str(n)[::-1])

def palindrome(num):
    is_palindrome = lambda chunk: int(chunk) > 9 and chunk == chunk[::-1]
    if not isinstance(num, int) or num < 0: return 'Not valid'
    i = 0
    while(True):
        if is_palindrome(str(num + i)): return num + i
        if is_palindrome(str(num - i)): return num - i
        i += 1


def palindrome(num):
        
    if not isinstance(num, int) or num < 0:
        return "Not valid"
    
    if num > 9 and str(num) == str(num)[::-1]:
        return num

    num_down = num
    num_up = num
    
    d = {}
    while not d:
        num_down -= 1
        num_up += 1

        if str(num_down) == str(num_down)[::-1] and num_down > 9:
            d['?'] = num_down
    
        if str(num_up) == str(num_up)[::-1] and num_up > 9:
            d['?'] = num_up

    return d.get('?', num)

def palindrome(num):
    if not isinstance(num, int) or num < 0: return 'Not valid'
    n = 1
    num = max(num, 11)
    minus, plus = num, num
    f = lambda x: str(x) == str(x)[::-1]
    pal = 0 if not f(num) else num
    while not pal:
        plus += n
        if f(plus):
            return plus
        minus -= n
        if f(minus):
            return minus
    return pal

is_palindrome = lambda x: x > 10 and str(x) == str(x)[::-1]


def palindrome(num):
    if not isinstance(num, int) or num < 0:
        return "Not valid"
    
    smaller, larger = num, num
    
    while True:
        checks = is_palindrome(smaller), is_palindrome(larger)
        
        if checks == (True, False): return smaller
        if checks == (False, True): return larger
        if checks == (True,  True): return larger
        
        smaller -= 1
        larger  += 1

def is_palindrome(n):
    s = str(n)
    return s == s[::-1]

def palindrome(num):
    if not isinstance(num, int) or num < 0:
        return "Not valid"
    if num < 17:
        return 11
    inf = next(n for n in range(num, 0, -1) if is_palindrome(n))
    sup = next(n for n in range(num, 2*num) if is_palindrome(n))
    mean = (inf + sup) / 2
    return sup if num >= mean else inf

from itertools import count
def palindrome(num):
    return next(c for b in count(0) for c in (num + b, num - b) if c > 9 and c == int(str(c)[::-1])) if isinstance(num, int) and num >= 0 else 'Not valid'

def findR(num):
    while True:
        if str(num)==str(num)[::-1]:
            return num
        num+=1
def findL(num):
    while True:
        if str(num)==str(num)[::-1]:
            return num
        num-=1
def palindrome(num):
    if type(num)!=int or num<0:
        return 'Not valid'
    if num<=10:
        return 11
    else:
        if findR(num)-num<=num-findL(num):
            return findR(num)
        else:
            return findL(num)


def is_pali(num):
    return str(num) == str(num)[::-1] and num > 9

def palindrome(num):
    if type(num) != int or str(num) != str(int(num)) or int(num) < 0:
        return 'Not valid'
    n = 0
    if num <= 11:
        return 11
    while n < num:
        test1 = num - n
        test2 = num + n
        if is_pali(test2):
            return num + n
        elif is_pali(test1):
            return num - n
        n += 1

""" Solution without loops ! """

""" Define the first segment of what wwould be a "not far away palindrome" based on "num" :
            num = 1258  -> midPart = 12  ( -> would give "1221" )
            num = 459   -> midPart = 45  ( -> would give "454"  )
    
    Check for lower and upper values (in case num is near of change of decade, upperbond or lowerbond)
    and define 3 possible parts of palindromes:
            num = 1258  -> 12  ->  lowPart  = 11
                                   midPart  = 12
                                   highPart = 13
            num = 459   -> 45  ->  lowPart  = 44
                                   midPart  = 45
                                   highPart = 46
                                   
    Construct palindromes according to each part an the parity of the length of the original number:
            num = 1258  -> lPal = 1111 ; mPal = 1221 ; hPal = 1331
            num = 459   -> lPal = 444  ; mPal = 454  ; hPal = 464
    
    Sort the result with tuples defined as:     (abs(num-newPal), -newPal)
    This way, the nearest new palindrome value are first, and if two values of "abs(num-newPal)"
    are equal, the second element of the tuple ensure to find the highest one as first element of 
    the sorted list of tuples.
    return the opposite of the second element of the first tuple, which is so "newPal".
    
    Edge cases:  num = 1999 -> lPal = 1881 ; mPal = 1991 ; hPal = 2002  =>  return 2002
                 num = 801  -> lPal = 797  ; mPal = 808  ; hPal = 818   =>  return 797
                 num = 1002 -> lPal = 99(!); mPal = 1001 ; hPal = 1111  =>  return 1001
"""

def nextPal(sPart, ls): return int( sPart + sPart[:len(sPart)-ls%2][::-1] )

def palindrome(num):
    if type(num) != int or num <= 0: return "Not valid"
    
    s = str(num)
    midPart  = s[:(len(s)+1)//2]
    lowPart  = str(int(midPart)-1)
    highPart = str(int(midPart)+1)
    lPal, mPal, hPal = nextPal(lowPart, len(s)), nextPal(midPart, len(s)), nextPal(highPart, len(s))
    
    return 11 if num <= 16 else -sorted( (abs(num-pal), -pal)  for pal in [lPal, mPal, hPal] )[0][1]