This question already has answers here:
Removing duplicates from a list of lists
(16 answers)
How to remove duplicate lists in a list of list? [duplicate]
(2 answers)
Removing duplicates from list of lists in Python
(5 answers)
Python and remove duplicates in list of lists regardless of order within lists
(2 answers)
Remove duplicated lists in list of lists in Python
(4 answers)
Closed 3 years ago.
Given list that looks like:
list = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
How do I return
final_list = [["A"], ["B"], ["A", "B"], ["A", "B", "C"]]
Note that I treat ["A","B"] to be same as ["B","A"]
and ["A","B","C"] same as ["B", "A", "C"].
Try this :
list_ = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
l = list(map(list, set(map(tuple, map(set, list_)))))
Output :
[['A', 'B'], ['B'], ['A', 'B', 'C'], ['A']]
This process goes through like :
First convert each sub-list into a set. Thus ['A', 'B'] and ['B', 'A'] both are converted to {'A', 'B'}.
Now convert each of them to a tuple for removing duplicate items as set() operation can not be done with set sub-items in the list.
With set() operation make a list of unique tuples.
Now convert each tuple items in the list into list type.
This is equivalent to :
list_ = [['A'], ['B'], ['A', 'B'], ['B', 'A'], ['A', 'B', 'C'], ['B', 'A', 'C']]
l0 = [set(i) for i in list_]
# l0 = [{'A'}, {'B'}, {'A', 'B'}, {'A', 'B'}, {'A', 'B', 'C'}, {'A', 'B', 'C'}]
l1 = [tuple(i) for i in l0]
# l1 = [('A',), ('B',), ('A', 'B'), ('A', 'B'), ('A', 'B', 'C'), ('A', 'B', 'C')]
l2 = set(l1)
# l2 = {('A', 'B'), ('A',), ('B',), ('A', 'B', 'C')}
l = [list(i) for i in l2]
# l = [['A', 'B'], ['A'], ['B'], ['A', 'B', 'C']]
l = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
[list(i) for i in {tuple(sorted(i)) for i in l}]
One possible solution:
lst = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
print([
list(i)
for i in sorted(
set(
tuple(sorted(i))
for i in lst
),
key=lambda k: (len(k), k)
)
])
Prints:
[['A'], ['B'], ['A', 'B'], ['A', 'B', 'C']]
When the data you want to handle has to be both unique and unordered, a better choice of data structure are set and frozenset.
A set is an unordered container of unique values.
A frozenset is a set which cannot be mutated, it is thus hashable which allows it to be contained into another set.
Example
lst = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
data = {frozenset(el) for el in lst}
print(data)
Output
{frozenset({'B'}), frozenset({'A', 'B'}), frozenset({'A', 'C', 'B'}), frozenset({'A'})}
The following is a equality partition. It works on any list of any type that has equality defined for it. This is worse than a hash partition as it is quadratic time.
def partition(L, key=None):
if key is None:
key = lambda x: x
parts = []
for item in L:
for part in parts:
if key(item) == key(part[0]):
part.append(item)
break
else:
parts.append([item])
return parts
def unique(L, key=None):
return [p[0] for p in partition(L, key=key)]
alist = [["A"], ["B"], ["A","B"], ["B","A"], ["A","B","C"], ["B", "A", "C"]]
unique(alist)
# results in [['A'], ['B'], ['A', 'B'], ['B', 'A'], ['A', 'B', 'C'], ['B', 'A', 'C']]
unique(alist, key=lambda v: tuple(sorted(v)))
# results in [['A'], ['B'], ['A', 'B'], ['A', 'B', 'C']]
Related
I have a list like this:
my_list = [['a', 'b', 'c', 'd'], ['a', 'e', 'f', 'd'], ['a', 'b', 'c', 'g'], ['d', 'e', 'f', 'd']]
and I want to compare its items with another list:
main_list = ["a", "b", "f", "d"]
And I want to return the indexes that they differ. My code so far looks like this:
differences = []
my_list = [['a', 'b', 'c', 'd'], ['a', 'e', 'f', 'd'], ['a', 'b', 'c', 'g'], ['d', 'e', 'f', 'd']]
main_list = ["a", "b", "f", "d"]
for i in range(len(my_list)):
for index, (first, second) in enumerate(zip(my_list[i], main_list), start=1):
if first != second:
differences.append(index)
print(differences)
With the above code I get this output:
[3, 2, 3, 4, 1, 2]
Which is exactly the indices the main list differs with the original list. However I would like to get this list as an output, which gives me a nested list of which each index is the indices the main list differs with my_list[0], then with my_list[1] and so on:
[[3], [2], [3, 4], [1, 2]]
I would appreciate some help on modifying the code to get the ideal output.
Thanks!
my_list = [['a', 'b', 'c', 'd'], ['a', 'e', 'f', 'd'], ['a', 'b', 'c', 'g'], ['d', 'e', 'f', 'd']]
main_list = ["a", "b", "f", "d"]
out = []
for subl in my_list:
out.append([i for i, (a, b) in enumerate(zip(subl, main_list), 1) if a != b])
print(out)
Prints:
[[3], [2], [3, 4], [1, 2]]
Or one liner:
out = [[i for i, (a, b) in enumerate(zip(subl, main_list), 1) if a != b] for subl in my_list]
print(out)
How to replace the first value in a list of lists with a new value?
list_of_lists = [["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
new_values = [1, 2, 3]
for i in list_of_lists:
for n in range(len(new_values)):
list_of_lists[n][0] = new_values[n]
Desired output
list_of_lists = [[1, "b" ,"c"], [2, "e", "f"], [3, "h", "i"]]
This one is actually quite simple
list_of_lists = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
new_values = [1, 2, 3]
for sub_list in list_of_lists:
sub_list[0] = new_values.pop(0)
This iterates over the lists and removes the first value of new_values each time.
Your code produces the correct output, but you don't need the outside loop:
for i in list_of_lists:
Notice you never use i.
But really, there's a better way. Python makes it simple to avoid awkward structures like range(len(new_values)). In this case you can simply zip your lists together and loop over that construct. This avoids the need to keep track of indexes — you just get the value and the list you want to alter in each loop iteration:
list_of_lists = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
new_values = [1, 2, 3]
for newVal, subList in zip(new_values, list_of_lists):
subList[0] = newVal
list_of_lists will now look like:
[[1, 'b', 'c'], [2, 'e', 'f'], [3, 'h', 'i']]
Try:
list_of_lists = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
new_values = [1, 2, 3]
for n in range(len(list_of_lists)):
list_of_lists[n][0] = new_values[n]
Also, as a quicker way to set up the list_of_lists, one could say:
list_of_lists = [list('abc'), list('def'), list('ghi')]
Further, to avoid modifying the OP's original code as much as possible, one could insert the following line at the top, to define each letter variable to have its own character:
a, b, c, d, e, f, g, h, i = list('abcdefghi')
Using enumerate to generate the index and list comprehension works too:
new_l = [[new_values[i]] + l[1:] for i, l in enumerate(list_of_lists)]
>>> new_l
[[1, 'b', 'c'], [2, 'e', 'f'], [3, 'h', 'i']]
I want to iterate over a map's values and compare elements of a list to see if at least 3 elements match in the same order, and then have a list returned with the keys that match the condition.
prefs = {
's1': ["a", "b", "c", "d", "e"],
's2': ["c", "d", "e", "a", "b"],
's3': ["a", "b", "c", "d", "e"],
's4': ["c", "d", "e", "b", "e"],
's5': ["c", "d", "e", "a", "b"]
}
Here is a sample map. In this example keys s1, and s3 have at least three elements in the list value that match "a", "b", "c". So s1, and s3 should be returned like this s1 -- s3. Similarly s2 and s4 match so that should also be returned, but s2 has multiple matches because it matches with s5 as well so s2 -- s5 should be returned. I want to return all possible matches for each key-value pair in a list.
The return output should be something like:
[[s1--s3], [s2--s4], [s2--s5], [s4--s5]]
I'm unable to figure out how I can iterate over each value in the map, but here is a snippet of element-wise comparison. I'm wondering if I can set a counter, and check to see if match_cnt > 3 and then return the keys in a list.
a = ["a", "b", "c", "d", "e"]
b = ["a", "c", "b", "d", "e"]
match_cnt = 0
if len(a) == len(b):
for i in range(len(a)):
if a[i] == b[i]:
print(a[i], b[i])
Also, want some knowledge on the runtime of this algorithm.
Complete code solution would be appreciated.
I had been advised to open a new question here
You can make use .items() to iterate over the map, then it's just matching the first 3 list items using a slice:
prefs = {
's1': ["a", "b", "c", "d", "e"],
's2': ["c", "d", "e", "a", "b"],
's3': ["a", "b", "c", "d", "e"],
's4': ["c", "d", "e", "b", "e"],
's5': ["c", "d", "e", "a", "b"]
}
results = []
for ki, vi in prefs.items():
for kj, vj in prefs.items():
if ki == kj: # skip checking same values on same keys !
continue
if vi[:3] == vj[:3]: # slice the lists to test first 3 characters
match = tuple(sorted([ki, kj])) # sort results to eliminate duplicates
results.append(match)
print (set(results)) # print a unique set
Returns:
set([('s1', 's3'), ('s4', 's5'), ('s2', 's5'), ('s2', 's4')])
Edit:
To check all possible combinations, you can use combinations() from itertools. iCombinations/jCombinations are preserving order with a length of 3 list items:
from itertools import combinations
prefs = {
's1': ["a", "b", "c", "d", "e"],
's2': ["c", "d", "e", "a", "b"],
's3': ["a", "b", "c", "d", "e"],
's4': ["c", "d", "e", "b", "e"],
's5': ["c", "d", "e", "a", "b"]
}
results = []
for ki, vi in prefs.items():
for kj, vj in prefs.items():
if ki == kj: # skip checking same values on same keys !
continue
# match pairs from start
iCombinations = [vi[n:n+3] for n in range(len(vi)-2)]
jCombinations = [vj[n:n+3] for n in range(len(vj)-2)]
# match all possible combinations
import itertools
iCombinations = itertools.combinations(vi, 3)
jCombinations = itertools.combinations(vj, 3)
if any([ic in jCombinations for ic in iCombinations]): # checking all combinations
match = tuple(sorted([ki, kj]))
results.append(match)
print (set(results)) # print a unique set
This returns:
set([('s1', 's3'), ('s2', 's5'), ('s3', 's5'), ('s2', 's3'), ('s2', 's4'), ('s1', 's4'), ('s1', 's5'), ('s3', 's4'), ('s4', 's5'), ('s1', 's2')])
I've tried to be as detailed as possible. This should be an example how you can often work your way through such a problem by inserting a lot of print messages to create a log of what's going on.
prefs = {
's1': ["a", "b", "c", "d", "e"],
's2': ["c", "d", "e", "a", "b"],
's3': ["a", "b", "c", "d", "e"],
's4': ["c", "d", "e", "b", "e"],
's5': ["c", "d", "e", "a", "b"]
}
# Get all items of prefs and sort them by key. (Sorting might not be
# necessary, that's something you'll have to decide.)
items_a = sorted(prefs.items(), key=lambda item: item[0])
# Make a copy of the items where we can delete the processed items.
items_b = items_a.copy()
# Set the length for each compared slice.
slice_length = 3
# Calculate how many comparisons will be necessary per item.
max_shift = len(items_a[0][1]) - slice_length
# Create an empty result list for all matches.
matches = []
# Loop all items
print("Comparisons:")
for key_a, value_a in items_a:
# We don't want to check items against themselves, so we have to
# delete the first item of items_b every loop pass (which would be
# the same as key_a, value_a).
del items_b[0]
# Loop remaining other items
for key_b, value_b in items_b:
print("- Compare {} to {}".format(key_a, key_b))
# We have to shift the compared slice
for shift in range(max_shift + 1):
# Start the slice at 0, then shift it
start = 0 + shift
# End the slice at slice_length, then shift it
end = slice_length + shift
# Create the slices
slice_a = value_a[start:end]
slice_b = value_b[start:end]
print(" - Compare {} to {}".format(slice_a, slice_b), end="")
if slice_a == slice_b:
print(" -> Match!", end="")
matches += [(key_a, key_b, shift)]
print("")
print("Matches:")
for key_a, key_b, shift in matches:
print("- At positions {} to {} ({} elements), {} matches with {}".format(
shift + 1, shift + slice_length, slice_length, key_a, key_b))
Which prints:
Comparisons:
- Compare s1 to s2
- Compare ['a', 'b', 'c'] to ['c', 'd', 'e']
- Compare ['b', 'c', 'd'] to ['d', 'e', 'a']
- Compare ['c', 'd', 'e'] to ['e', 'a', 'b']
- Compare s1 to s3
- Compare ['a', 'b', 'c'] to ['a', 'b', 'c'] -> Match!
- Compare ['b', 'c', 'd'] to ['b', 'c', 'd'] -> Match!
- Compare ['c', 'd', 'e'] to ['c', 'd', 'e'] -> Match!
- Compare s1 to s4
- Compare ['a', 'b', 'c'] to ['c', 'd', 'e']
- Compare ['b', 'c', 'd'] to ['d', 'e', 'b']
- Compare ['c', 'd', 'e'] to ['e', 'b', 'e']
- Compare s1 to s5
- Compare ['a', 'b', 'c'] to ['c', 'd', 'e']
- Compare ['b', 'c', 'd'] to ['d', 'e', 'a']
- Compare ['c', 'd', 'e'] to ['e', 'a', 'b']
- Compare s2 to s3
- Compare ['c', 'd', 'e'] to ['a', 'b', 'c']
- Compare ['d', 'e', 'a'] to ['b', 'c', 'd']
- Compare ['e', 'a', 'b'] to ['c', 'd', 'e']
- Compare s2 to s4
- Compare ['c', 'd', 'e'] to ['c', 'd', 'e'] -> Match!
- Compare ['d', 'e', 'a'] to ['d', 'e', 'b']
- Compare ['e', 'a', 'b'] to ['e', 'b', 'e']
- Compare s2 to s5
- Compare ['c', 'd', 'e'] to ['c', 'd', 'e'] -> Match!
- Compare ['d', 'e', 'a'] to ['d', 'e', 'a'] -> Match!
- Compare ['e', 'a', 'b'] to ['e', 'a', 'b'] -> Match!
- Compare s3 to s4
- Compare ['a', 'b', 'c'] to ['c', 'd', 'e']
- Compare ['b', 'c', 'd'] to ['d', 'e', 'b']
- Compare ['c', 'd', 'e'] to ['e', 'b', 'e']
- Compare s3 to s5
- Compare ['a', 'b', 'c'] to ['c', 'd', 'e']
- Compare ['b', 'c', 'd'] to ['d', 'e', 'a']
- Compare ['c', 'd', 'e'] to ['e', 'a', 'b']
- Compare s4 to s5
- Compare ['c', 'd', 'e'] to ['c', 'd', 'e'] -> Match!
- Compare ['d', 'e', 'b'] to ['d', 'e', 'a']
- Compare ['e', 'b', 'e'] to ['e', 'a', 'b']
Matches:
- At positions 1 to 3 (3 elements), s1 matches with s3
- At positions 2 to 4 (3 elements), s1 matches with s3
- At positions 3 to 5 (3 elements), s1 matches with s3
- At positions 1 to 3 (3 elements), s2 matches with s4
- At positions 1 to 3 (3 elements), s2 matches with s5
- At positions 2 to 4 (3 elements), s2 matches with s5
- At positions 3 to 5 (3 elements), s2 matches with s5
- At positions 1 to 3 (3 elements), s4 matches with s5
It's still unclear, what your output really should be. However, I think you'll have no problems in converting the above code to your needs.
I'm trying to count the number of occurrences of elements within a list, if such elements are also lists. The order is also important.
[PSEUDOCODE]
lst = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
print( count(lst) )
> { ['a', 'b', 'c'] : 2, ['d', 'e', 'f']: 1, ['c', 'b', 'a']: 1 }
One important factor is that ['a', 'b', 'c'] != ['c', 'b', 'a']
I have tried:
from collections import counter
print( Counter([tuple(x) for x in lst]) )
print( [[x, list.count(x)] for x in set(lst)] )
Which both resulted in ['a', 'b', 'c'] = ['c', 'b', 'a'], one thing i didn't want
I also tried:
from collections import counter
print( Counter( lst ) )
Which only resulted in error; since lists can't be used as keys in dicts.
Is there a way to do this?
You can't have list as a key to the dict because dictionaries only allows immutable objects as it's key. Hence you need to firstly convert your objects to tuple. Then you may use collection.Counter to get the count of each tuple as:
>>> from collections import Counter
>>> my_list = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
# v to type-cast each sub-list to tuple
>>> Counter(tuple(item) for item in my_list)
Counter({('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1})
just use collections.Counter on some equivalent type but hashable: the tuple:
import collections
lst = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
c = collections.Counter(tuple(x) for x in lst)
print(c)
result:
Counter({('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1})
Lists are not hashable, but you can use tuples as a workaround:
l = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
new_l = list(map(tuple, l))
final_l = {a:new_l.count(a) for a in new_l}
Output:
{('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1}
Or, if you really want to use lists, you can create a custom class to mimic the functionality of a dictionary hashing lists:
class List_Count:
def __init__(self, data):
new_data = list(map(tuple, data))
self.__data = {i:new_data.count(i) for i in new_data}
def __getitem__(self, val):
newval = [b for a, b in self.__data.items() if list(a) == val]
if not newval:
raise KeyError("{} not found".format(val))
return newval[0]
def __repr__(self):
return "{"+"{}".format(', '.join("{}:{}".format(list(a), b) for a, b in self.__data.items()))+"}"
l = List_Count([ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ])
print(l)
print(l[['a', 'b', 'c']])
Output:
{['a', 'b', 'c']:2, ['d', 'e', 'f']:1, ['c', 'b', 'a']:1}
2
Another implementation with lists
l1 = [["a", "b", "c"], ["b", "c", "d"], ["a", "b", "c"], ["c", "b", "a"]]
def unique(l1):
l2 = []
for element in l1:
if element not in l2:
l2.append(element)
return l2
l2 = unique(l1)
for element in l2:
print(element, l1.count(element))
and if you want an dictionary from that you can just change the last part to
output = {element:l1.count(element) for element in unique(l1)}
Don't Use list as variable name.
You can try this approach if you don't want to use any module :
list_1 = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
track={}
for i in list_1:
if tuple(i) not in track:
track[tuple(i)]=1
else:
track[tuple(i)]+=1
print(track)
outoput:
{('a', 'b', 'c'): 2, ('d', 'e', 'f'): 1, ('c', 'b', 'a'): 1}
You can also use default dict:
list_1 = [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['a', 'b', 'c'], ['c', 'b', 'a'] ]
track={}
import collections
d=collections.defaultdict(list)
for j,i in enumerate(list_1):
d[tuple(i)].append(j)
print(list(map(lambda x:{x:len(d[x])},d.keys())))
For example, list to_be consists of: 3 of "a", 4 of "b", 3 of "c", 5 of "d"...
to_be = ["a", "a", "a", "b", "b", "b", "b", "c", "c", "c", "d", "d", "d", "d", "d", ...]
Now I want it to be like this:
done = ["a", "b", "c", "d", ... , "a", "b", "c", "d", ... , "b", "d", ...] (notice: some items are more than others as in amounts, but they need to be still in a pre-defined order, alphabetically for example)
What's the fastest way to do this?
Presuming I am understanding what you want, it can be done relatively easily by combining itertools.zip_longest, itertools.groupby and itertools.chain.from_iterable():
We first group the items into sets (the "a"s, the "b"s, etc...), we zip them up to get them in the order your want (one from each set), use chain to produce a single list, and then remove the None values introduced by the zipping.
>>> [item for item in itertools.chain.from_iterable(itertools.zip_longest(*[list(x) for _, x in itertools.groupby(to_be)])) if item]
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
You may want to separate out some of the list comprehensions to make it a bit more readable, however:
>>> groups = itertools.zip_longest(*[list(x) for _, x in itertools.groupby(to_be)])
>>> [item for item in itertools.chain.from_iterable(groups) if item]
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
(The given version is for 3.x, for 2.x, you will want izip_longest().)
As always, if you expect empty strings, 0, etc... then you will want to do if item is not None, and if you need to keep None values in tact, create a sentinel object and check for identity against that.
You could also use the roundrobin() recipe given in the docs, as an alternative to zipping, which makes it as simple as:
>>> list(roundrobin(*[list(x) for _, x in itertools.groupby(to_be)]))
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
As a final note, the observant might note me making lists from the groupby() generators, which may seem wasteful, the reason comes from the docs:
The returned group is itself an iterator that shares the underlying
iterable with groupby(). Because the source is shared, when the
groupby() object is advanced, the previous group is no longer visible.
So, if that data is needed later, it should be stored as a list.
to_be = ["a", "a", "a", "b", "b", "b", "b", "c", "c", "c", "d", "d", "d", "d", "d"]
counts = collections.Counter(to_be)
answer = []
while counts:
answer.extend(sorted(counts))
for k in counts:
counts[k] -= 1
counts = {k:v for k,v in counts.iteritems() if v>0}
Now, answer looks like this:
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
I'm not sure if this is fastest, but here's my stab at it:
>>> d = defaultdict(int)
>>> def sort_key(a):
... d[a] += 1
... return d[a],a
...
>>> sorted(to_be,key=sort_key)
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'd', 'd']
wrapped up in a function:
def weird_sort(x):
d = defaultdict(int)
def sort_key(a):
d[a] += 1
return (d[a],a)
return sorted(x,key=sort_key)
Of course, this requires that the elements in your iterable be hashable.
A bit less elegant than Lattyware's:
import collections
def rearrange(l):
counts = collections.Counter(l)
output = []
while (sum([v for k,v in counts.items()]) > 0):
output.extend(sorted([k for k, v in counts.items() if v > 0))
for k in counts:
counts[k] = counts[k] - 1 if counts[k] > 0 else 0
return counts
Doing it "by hand and state machinne" should be way more efficient -
but for relatively small lists (<5000), you should have no problem taking vantage of
Python goodies doing this:
to_be = ["a", "a", "a", "b", "b", "b", "b", "c", "c", "c", "d", "d", "d", "d", "d","e", "e"]
def do_it(lst):
lst = lst[:]
result = []
while True:
group = set(lst)
result.extend(sorted(group))
for element in group:
del lst[lst.index(element)]
if not lst:
break
return result
done = do_it(to_be)
The "big O" complexity of the function above should be really BIG. I had not event ried to figure it out.