# Task

Write a function `deNico`/`de_nico()` that accepts two parameters:
- `key`/`$key` - string consists of unique letters and digits
- `message`/`$message` - string with encoded message 

and decodes the `message` using the `key`.  

First create a numeric key basing on the provided `key` by assigning each letter position in which it is located after setting the letters from `key` in an alphabetical order.

For example, for the key `crazy` we will get `23154` because of `acryz` (sorted letters from the key).  
Let's decode  `cseerntiofarmit on  ` using our `crazy` key.

```
1 2 3 4 5
---------
c s e e r
n t i o f
a r m i t
  o n   
```

After using the key:
```
2 3 1 5 4
---------
s e c r e
t i n f o
r m a t i
o n
```

# Notes 

- The `message` is never shorter than the `key`.
- Don't forget to remove trailing whitespace after decoding the message

# Examples

Check the test cases for more examples.

# Related Kata

[Basic Nico - encode](https://www.codewars.com/kata/5968bb83c307f0bb86000015)

Difficulty: introductory

Starter code:

def de_nico(key,msg):
	

Solutions:
def de_nico(key, msg):
    ll, order, s = len(key), [sorted(key).index(c) for c in key], ''
    while msg:
        s, msg = s + ''.join(msg[i] for i in order if i < len(msg)), msg[ll:]
    return s.strip()

def de_nico(key,msg):
    
    decoder = []
    
    # assign key letters numbers according to alphabetized/sorted indices
    for letter in key:
        decoder.append(sorted(key).index(letter))

    # break msg into segments based on key length
    msg_segs = [msg[i:(i+len(key))] for i in range(0, len(msg), len(key))]
    
    # enumerate segments along their ranges
    enum_segs = []
    for seg in msg_segs:
        enum_segs.append(dict(zip(range(len(seg)),seg)))

    # read segs back into decoded_msg by codon in decoder, excepting KeyErrors out to account for final
    # seg length < len(decoder)
    decoded_msg = []
    for seg in enum_segs:
        for codon in decoder:
            try:
                decoded_msg.append(seg[codon])
            except KeyError:
                continue
    
    return ((''.join(decoded_msg)).rstrip())

from operator import itemgetter
def de_nico(key,msg):
    #keyDict = dict(zip(sorted(key), range(1, len(key)+1)))
    #encryptkey = "".join([str(keyDict[x]) for x in key])
    decryptkey, _ = zip( *sorted(zip(range(1, len(key)+1), key), key = itemgetter(1) ))
    decryptkey = "".join(str(x) for x in decryptkey)
    chunksize = len(decryptkey)
    chunks = [msg[y-chunksize:y] for y in range(chunksize, len(msg)+chunksize, chunksize)]
    #chunks[-1] += " "*(len(key) - len(chunks[-1])) ## add whitespaces accordingly if the last chunk happens to be too short    
    for i, chunk in enumerate(chunks):
        chunkSorted, _ = zip( *sorted( zip(chunk, decryptkey), key = itemgetter(1) ))
        chunks[i] = "".join(chunkSorted)
    return "".join(chunks).rstrip()

import itertools
def de_nico(key,msg):
    pack =[list(range(len(key)))]+list(list(msg[i:i+len(key)]) for i in range(0,len(msg),len(key)))
    sor = [sorted(key).index(i) for i in key]
    sorting = sorted(itertools.zip_longest(*pack,fillvalue=""), key=lambda col: sor.index(col[0]))
    return "".join(["".join(j) for i,j in enumerate(itertools.zip_longest(*sorting,fillvalue=" ")) if i>0]).strip(" ")

def de_nico(key,msg):
    result = ''
    counter = -1
    while len(result) < len(msg):
        counter += 1
        for i in [sorted(key).index(c) for c in key]:
            try:
                result += msg[i+counter*len(key)]
            except:
                continue
    return result.strip()


def de_nico(key,msg):
    sorted_key = sorted(key)
    num_key = []
    for chr in key:
        num_key.append(sorted_key.index(chr))

    result = ''
    start = 0
    end = len(key)
    while start < len(msg):
        chunk = msg[start : end]
        for index in num_key:
            if index < len(chunk):
                result += chunk[index]
        start = end
        end += len(key)

    return result.strip()

de_nico=lambda k,m: (lambda k: "".join((lambda g: "".join(g[p] for p in k if p<len(g)))(m[i*len(k):(i+1)*len(k)]) for i in range(len(m)//len(k)+1)).strip())((lambda s: [s.index(l) for l in k])(sorted(k)))

def de_nico(key,msg):
    num_key = ''.join([str(id) for i in key for id, item in enumerate(sorted(key), 1) if item == i])
    cut_msg = [msg[i:i+len(num_key)] for i in range(0, len(msg), len(num_key))]
    d_msg = [''.join([item for i in num_key for id, item in enumerate(list(x), 1) if id == int(i)]) for x in cut_msg]
    return ''.join(d_msg).rstrip()

from itertools import chain, zip_longest

def de_nico(key, msg):
    columns = [msg[n::len(key)] for n in range(len(key))]
    key = (n for n, c in sorted(enumerate(key), key=lambda k: k[1]))
    return ''.join(chain(*zip_longest(*sorted(columns, key=lambda k: next(key)), fillvalue=''))).strip()

from itertools import cycle


def de_nico(key, msg):
    code = tuple(sorted(key).index(k) + 1 for k in key)
    code_cycle = cycle(code)
    key_cycle = cycle(range(1, len(key) + 1))
    msg_encrypted = [(k, next(key_cycle)) for k in msg]
    result = []
    while msg_encrypted:
        try:
            index = next(code_cycle)
            found = next(p for p in msg_encrypted if p[1] == index)
            msg_encrypted.remove(found)
            result.append(found[0])
        except StopIteration:
            pass
    return ''.join(result).strip()