Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pythonic way to filter list for elements with unique length

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']
like image 571
Ilja Avatar asked Dec 10 '22 23:12

Ilja


2 Answers

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.)

like image 60
abarnert Avatar answered Dec 29 '22 07:12

abarnert


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.

like image 30
Shashank Avatar answered Dec 29 '22 07:12

Shashank