Split words into alphabetic dictionary rxpy

Viewed 428

I am learning RxPY , so I need to write some code which can split each word by its first character. The results must look something like this:

{'a': ['a'], 't': ['the','the'], 'l': ['low','lazy']}

What I've tried.

from rx import Observable , Observer

list =['A', 'The', 'the', 'LAZY', 'Low']

o = Observable . from_ ( list )\
. filter (lambda i: i[0] == 'A' or 'Z' )\

words = o.map(lambda s: s.lower().split())

word_each = words.flat_map(lambda s: s)

ss = word_each.to_dict(lambda x: x[:1], lambda x : x)\
    .subscribe(lambda val: print(val))

So, how can I solve this problem? I am thinking about grouping each word by it's first character but I dont know how.

[CLOSED]
4 Answers

I know nothing about RxPy, but you can do it in one line with vanilla python using dict and list comps

  d = {el[0].lower(): [e.lower() for e in lst if e[0].lower() == el[0].lower()] for el in lst}

Using rx, if you really want to do it in a difficult way.

>>> from rx import Observable
>>> from collections import defaultdict
>>> source = Observable.from_(['A', 'The', 'the', 'LAZY', 'Low'])
>>> result = defaultdict(list)
>>> def add(value):
...     value_content = '{0}'.format(value)
...     result[value_content[0].lower()].append(value_content)
... 
>>> s = source.subscribe(on_next=lambda value: add(value), on_completed=lambda: print('Finished'))
Finished
>>> result
defaultdict(<class 'list'>, {'a': ['A'], 't': ['The', 'the'], 'l': ['LAZY', 'Low']})

Use dict(result) as shown in Chiheb Nexus' answer if you need this in the form of a dictionary.

I changed the name of your list to my_list.

>>> my_list =['A', 'The', 'the', 'LAZY', 'Low']
>>> from itertools import groupby
>>> {key: list(val) for (key, val) in  groupby(sorted(my_list), key=lambda x: x[0].lower())}
{'a': ['A'], 't': ['The', 'the'], 'l': ['LAZY', 'Low']}

You can use defaultdict module to accomplish the task. Here is an example:

from collections import defaultdict
my_list = ['A', 'The', 'the', 'LAZY', 'Low']

def split_words(a):
    b = defaultdict(list)
    for k in a:
        b[k[0].lower()].append(k.lower())
    return b

>>> split_words(my_list)
    defaultdict(list, {'a': ['a'], 'l': ['lazy', 'low'], 't': ['the', 'the']})
>>> dict(split_words(my_list))
    {'a': ['a'], 'l': ['lazy', 'low'], 't': ['the', 'the']}

Update May 2019 using RxPy v6

RxPy really shines when performing these types of transformations (although acknowledged you could equally apply a pragmatic solution in plain python).

Here is a straightforward solution:

from rx import Observable

list = ['A', 'The', 'the', 'LAZY', 'Low']

Observable.from_(list) \
    .map(lambda s: s.lower()) \
    .group_by(lambda s: s[0]) \
    .flat_map(lambda grp: grp.to_list()) \
    .to_dict(lambda grp: grp[0][0], lambda grp: grp) \
    .subscribe(print)

Output as requested:

# {'a': ['a'], 't': ['the', 'the'], 'l': ['lazy', 'low']}

The "algorithm" is:

  • Make the list of words an Observable.
  • Map over each word and convert to lowercase.
  • Group each word by its first letter.
  • Use flatmap to unnest as we convert each grouping to a list. At this point, the interim result looks as follows:

    ['a']
    ['the', 'the']
    ['lazy', 'low']
    
  • Now, use the to_dict operator to convert to a single dictionary, whose keys are the first letter of the first item in each grouping (list).

  • Subscribe to the Observable to execute the pipeline.
Related