## Task

Create a function that given a sequence of strings, groups the elements that can be obtained by rotating others, ignoring upper or lower cases. 

In the event that an element appears more than once in the input sequence, only one of them will be taken into account for the result, discarding the rest. 

## Input

Sequence of strings. Valid characters for those strings are uppercase and lowercase characters from the alphabet and whitespaces.

## Output

Sequence of elements. Each element is the group of inputs that can be obtained by rotating the strings. 

Sort the elements of each group alphabetically. 

Sort the groups descendingly by size and in the case of a tie, by the first element of the group alphabetically.

## Examples

```python
['Tokyo', 'London', 'Rome', 'Donlon', 'Kyoto', 'Paris', 'Okyot'] --> [['Kyoto', 'Okyot', 'Tokyo'], ['Donlon', 'London'], ['Paris'], ['Rome']]

['Rome', 'Rome', 'Rome', 'Donlon', 'London'] --> [['Donlon', 'London'], ['Rome']]

[] --> []
```

Difficulty: introductory

Starter code:

def group_cities(seq):
	

Solutions:
def group_cities(seq):
    result = []
    sort_result =[]
    seq = list(dict.fromkeys(seq)) #removing  duplicates
    for e, i in enumerate(seq):
        sort_result = [j for j in seq if len(j)==len(i) and j.lower() in 2*(i.lower())]
        if not sorted(sort_result) in result :
            result.append(sorted(sort_result))
    return(sorted(sorted(result),key=len,reverse=True))

from collections import Counter, defaultdict

def group_cities(seq):
    bases = defaultdict(lambda: defaultdict(list))
    for W in set(seq):
        w = W.lower()
        d = bases[ frozenset(Counter(w).items()) ]
        k = next( (w2 for w2 in d if w in w2), w*2)
        d[k].append(W)
        
    return sorted( [sorted(lst) for d in bases.values() for lst in d.values()],
                   key=lambda g: (-len(g),g[0]) )

from collections import deque

def group_cities(seq):
    result = []
    
    # Remove duplicates
    seq = sorted(set(seq))

    # Convert to lower case for comparisons
    simples = [c.lower() for c in seq]
    
    # Indices that have already been added to a set
    skip = set()
    
    # Look for matches
    for i, c1 in enumerate(simples):
        if i in skip:
            # Already matched
            continue
        city_match = [i]
        skip.add(i)
        
        # Create all the rolled versionos of this city name
        rolls = []
        roller = deque(c1)
        roller.rotate(1)
        while ''.join(roller) != c1:
            rolls.append(''.join(roller))
            roller.rotate(1)
        
        # See if a rolled name is present in any names later in the list
        for roll in rolls:
            for j, c2 in enumerate(simples[i + 1:], i + 1):
                if j in skip:
                    # Already matched
                    continue
                if c2 == roll:
                    # Found a matching name, add this index to the matches and skip set
                    skip.add(j)
                    city_match.append(j)
        
        # Convert matched indices back to original name
        result.append(sorted([seq[k] for k in city_match]))
    
    # Sort by decreasing length and then alphabetically
    result.sort(key=lambda a: (-len(a), a[0]))
    return result


def group_cities(seq):
    res = {}
    for w in seq:
        temp = [str(w[i:] + w[:i]).title() for i in range(1, len(w)) 
                if str(w[i:] + w[:i]).title() in seq]
        temp.append(w)
        res[frozenset(temp)] = sorted(set(temp))
    return sorted(res.values(), key=lambda x: (-len(x), x[0]))

def is_palindrome(a,b):
    if len(a)!=len(b):
        return False
    else:
        for i in range(1,len(a)):
            if a.lower()[i:] + a.lower()[:i] == b.lower():
                return True
        return False
def group_cities(seq): 
    ans=[]
    already_chosen=[]
    for term in seq:
        if term not in already_chosen:
            temp=[term]
            already_chosen.append(term)
            for thing in seq:
                if thing not in already_chosen and thing!=term and is_palindrome(thing,term):
                    temp.append(thing)
                    already_chosen.append(thing)
            ans.append(temp)
    for thing in ans:
        thing.sort()
    ans.sort(key=lambda x:x[0])
    ans.sort(key=len,reverse=True)
    return ans
                    


from collections import defaultdict

def key(s):
    s = s.lower().replace(' ', '')
    return min(s[i:] + s[:i] for i in range(len(s)))

def group_cities(seq): 
    result = defaultdict(list)
    for city in set(seq):
        result[key(city)].append(city)
    for cities in result.values():
        cities.sort()
    return sorted(result.values(), key=lambda cities: (-len(cities), cities[0]))

def group_cities(seq): 
    result = []
    for element in sorted(list(dict.fromkeys(seq)), key=str.lower):
        for group in result:
            if element.lower() in [group[0].lower()[r:] + group[0].lower()[:r] for r in range(len(group[0].lower()))]:
                group.append(element)
                break
        else:
            result.append([element])

    return sorted(result, key=len, reverse=True)


from collections import deque
from operator import itemgetter


def group_cities(seq):
    seq_by_length = {}
    for s in seq:
        l = len(s)
        if l in seq_by_length:
            seq_by_length[l].append(s)
        else:
            seq_by_length[l] = [s]

    groups = []
    for elems in seq_by_length.values():
        to_check = deque(set(elems))

        while to_check:
            cur_check = to_check.pop()
            group, check = [cur_check], cur_check.lower() * 2

            for c in to_check.copy():
                if c.lower() in check:
                    group.append(c)
                    to_check.remove(c)

            groups.append(sorted(group))

    return sorted(sorted(groups, key=itemgetter(0)), key=len, reverse=True)

from collections import defaultdict

def group_cities(l):
    def make_key(s):
        return min(s[-i:] + s[:-i] for i in range(len(s)))
    d = defaultdict(list)
    for item in sorted(set(l)):
        d[make_key(item.lower())].append(item)
    return sorted(d.values(), key=len, reverse=True)

from collections import defaultdict

def group_cities(seq): 
    key = lambda s: min(s[i:]+s[:i] for i in range(len(s)))
    d = defaultdict(set)
    for e in seq: d[key(e.lower())].add(e)
    return sorted((sorted(v) for v in d.values()), key=lambda x: (-len(x),x))