I want to filter a list, leaving only first elements with unique length. I wrote a function for it, but I believe there should be a simpler way of doing it:
def uniq_len(_list):
from itertools import groupby
uniq_lens = list(set([x for x, g in groupby(_list, len)]))
all_goods = []
for elem in _list:
elem_len = len(elem)
try:
good = uniq_lens.pop([i for i, x in enumerate(uniq_lens) if x==elem_len][0])
if good:
all_goods.append(elem)
except IndexError as _e:
#print all_goods
pass
return all_goods
In [97]: jones
Out[97]: ['bob', 'james', 'jim', 'jon', 'bill', 'susie', 'jamie']
In [98]: uniq_len(jones)
Out[98]: ['bob', 'james', 'bill']
If you just want any arbitrary string for each length, in arbitrary order, the easy way to do this is to first convert to a dict mapping lengths to strings, then just read off the values:
>>> {len(s): s for s in jones}.values()
dict_values(['jon', 'bill', 'jamie'])
If you want the first for each length, and you need to preserve the order, then that's just unique_everseen
from the itertools
recipes, with len
as the key:
>>> from more_itertools import unique_everseen
>>> list(unique_everseen(lst, key=len))
['bob', 'james', 'bill']
(If you pip install more-itertools
, it includes all of the recipes from the itertools
docs, plus a bunch of other helpful things.)
Getting the first item of the list with unique length (not necessarily in the same order as they appear in the list).
>>> lst = ['bob', 'james', 'jim', 'jon', 'bill', 'susie', 'jamie']
>>> list({len(x): x for x in reversed(lst)}.values())
['bob', 'bill', 'james']
Respecting the order of the original list, you can use an auxiliary set:
>>> seen = set()
>>> [x for x in lst if len(x) not in seen and seen.add(len(x)) is None]
['bob', 'james', 'bill']
For the above expression to work properly in succession, you have to make sure you reset seen
to an empty set each time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With