Maxim Rukhlov Maxim Rukhlov - 1 month ago 4
Python Question

Filter python dictionary with filter() to list of dictionary values

I have a dictionary consists of string or dictionaries

parameters = {
"date": {'date':"2015-12-13"},
"name": "Nick",
"product": "BT Adapter",
"transaction-id": ""
}


And i need to get list like
['2015-12-13', 'BT Adapter', 'Nick']
.

If it has no dictionaries in it,
print filter(lambda x: x if len(x) > 0 and type(x) is not dict else None, parameters.values())
works perfectly, but with dictionary in it i tried to extract it's value with

print filter(lambda x: x if len(x) > 0 and type(x) is not dict else map(lambda y: x[y], x.keys()), parameters.values())


and i get
AttributeError: 'str' object has no attribute 'keys'
.
How all values can be extracted?

Answer

You are misusing the filter function. The argument to filter is a predicate, which is a function that returns a true/false value and filter returns the elements from the second argument for which that function returns true.

For example:

print(list(filter(lambda x: 5, [1,2,3,4,5])))
[1, 2, 3, 4, 5]

Since bool(5) == True filter returns all the elements.

Since you pass as second argument the value parameters.values() there is no way to obtain your expected result by just passing a predicate to filter.

What you want to do is something like:

from itertools import chain

def listify(value):
    if isinstance(value, dict):
        return value.values()
    elif value:
        return [value]
    return ()

print(list(chain.from_iterable(map(listify, parameters.values()))))

So first you convert the values into sequences, and then you concatenate them using chain.from_iterable.

The empty values are removed by listify since it returns an empty sequence in that case. Sample run:

In [2]: parameters = {
   ...: "date": {'date':"2015-12-13"},
   ...: "name": "Nick",
   ...: "product": "BT Adapter",
   ...: "transaction-id": ""
   ...: }

In [3]: print(list(chain.from_iterable(map(listify, parameters.values()))))
['2015-12-13', 'Nick', 'BT Adapter']

Also: it doesn't make sense to write a complex lambda function with nested conditionals, so just use a def and write it properly. lambdas are fine only if they are extremely short.