How to use reduce() on a list and get a dictionary?

Viewed 1741

I'm trying to create a dictionary of word stems where the stems are the key and the value is the array of words that have the key as their stem. I've tried the following code

stem_word_dictionary = reduce(
        lambda accumulator, word_stem_tuple:
        accumulator.setdefault(word_stem_tuple[1], []).append(word_stem_tuple[0]),
        word_stem_tuple_list,
        {})

I get this error:

accumulator.setdefault(word_stem_tuple[1], []).append(word_stem_tuple[0]),
    AttributeError: 'NoneType' object has no attribute 'setdefault'

I don't understand what's happening here. I'm using an empty dictionary as the starting value for the reduce so not sure why it's "NoneType". Also disclaimer: I'm super new to python.

2 Answers

The reduction function used for reduce should always return an object of the same type as its input object, so that it can continue its reduction operation with the resulting object and the next object from the iterator. Your lambda function currently calls dict.setdefault(), a function that always returns None, so it naturally results in an error when it tries the next reduction operation with a None object.

For your purpose you should use the following loop instead of a reduction function:

stem_word_dictionary = {}
for w, k in word_stem_tuple_list:
    stem_word_dictionary.setdefault(k, []).append(w)

The issue is that the append() function does not return the list it is given. reduce() works by feeding the result of the previous invocation into the input of the next invocation. If the previous invocation does not return anything, it gets None, which is what the value of accumulator is following the first call.

Hop into any python REPL and do a simple:

a = []
a.append(1)

See how there is no output?

Related