AllJs
AllJs

Reputation: 1810

Python - List: How To Remove Empty Attributes From a List of Dictionaries With Nested Properties?

So I have the following list of dictionaries that I have initialized with either blank, None, or empty values. What is the proper way to go through each dictionary of the list and check if an attribute meets those criteria and removes them.

members = [{
        "member_id": 0,
        'title':  "Manager",
        'full_name': "John Doe",
        'first_name': None,
        'last_name': None,
        'age': 0,
},{
        "member_id": 1,
        'title':  " ",
        'full_name': "Jane Doe",
        'first_name': "Jane",
        'last_name': None,
        'age': 10,
},{...}]

[v for k, v in enumerate(members) if members[k] is not None]  

I should expect the following result:

members = [{
            'title':  "Manager",
            'full_name': "John Doe",
    },{
            "member_id": 1,
            'full_name': "Jane Doe",
            'first_name': "Jane",
            'age': 10,
    },{...}]

But it seems like my code is returning the same list. What am I doing wrong here. Thanks

EDIT: In case I have nested properties, such as address, How do I go about doing the same thing?

    members = [{
        "member_id": 0,
        'title':  "Manager",
        'full_name': "John Doe",
        'first_name': None,
        'last_name': None,
        'age': 0,
        'address': {
            'street_number': 123, 
            'street_name': None, 
            'city': "SF", 
            'state': "CA", 
            'zip': None, 
            'full_address': '123 Main Street, San Francisco, CA 94103'
        }
},{
        "member_id": 1,
        'title':  " ",
        'full_name': "Jane Doe",
        'first_name': "Jane",
        'last_name': None,
        'age': 10,
        'address': {
            'street_number': None, 
            'street_name': None, 
            'city': None, 
            'state': None, 
            'zip': None, 
            'full_address': '123 Main Street, San Francisco, CA 94103'
        }
}]

Upvotes: 2

Views: 146

Answers (3)

Andrej Kesely
Andrej Kesely

Reputation: 195408

One solution using recursion:

members = [{
        "member_id": 0,
        'title':  "Manager",
        'full_name': "John Doe",
        'first_name': None,
        'last_name': None,
        'age': 0,
        'address': {
            'street_number': 123,
            'street_name': None,
            'city': "SF",
            'state': "CA",
            'zip': None,
            'full_address': '123 Main Street, San Francisco, CA 94103'
        }
},{
        "member_id": 1,
        'title':  " ",
        'full_name': "Jane Doe",
        'first_name': "Jane",
        'last_name': None,
        'age': 10,
        'address': {
            'street_number': None,
            'street_name': None,
            'city': None,
            'state': None,
            'zip': None,
            'full_address': '123 Main Street, San Francisco, CA 94103'
        }
}]

def traverse(m):
    if isinstance(m, list):
        return list(v for v in (traverse(i) for i in m) if v)
    elif isinstance(m, dict):
        return dict((k, v) for k, v in ((k, traverse(v)) for k, v in m.items()) if v)
    else:
        return None if isinstance(m, str) and not m.strip() else m

filtered_members = traverse(members)

from pprint import pprint
pprint(filtered_members)

Prints:

[{'address': {'city': 'SF',
              'full_address': '123 Main Street, San Francisco, CA 94103',
              'state': 'CA',
              'street_number': 123},
  'full_name': 'John Doe',
  'title': 'Manager'},
 {'address': {'full_address': '123 Main Street, San Francisco, CA 94103'},
  'age': 10,
  'first_name': 'Jane',
  'full_name': 'Jane Doe',
  'member_id': 1}]

Upvotes: 1

Iain Shelvington
Iain Shelvington

Reputation: 32244

A dictionary can be made out of another dictionary while filtering out "falsy" values with a dictionary comprehension

{k: v for k, v in d.items() if v}

Looks like you expect other values to be filtered out like 0 and ' ' you can add these to the condition

{k: v for k, v in d.items() if v not in (None, ' ', 0)}

Then you can use a list comprehension with this same dictionary comprehension to get what you need

[{k: v for k, v in d.items() if v not in (None, ' ', 0)} for d in members]

EDIT:

For a recursive function that can filter multiple levels of dictionaries

def filter_dictionary(value):
    if isinstance(value, dict):
        return {k: filter_dictionary(v) for k, v in value.items() if v not in (None, ' ', 0)}
    elif value not in (None, ' ', 0):
        return value

[filter_dictionary(d) for d in members]

Upvotes: 2

KingMak
KingMak

Reputation: 1478

Something like this?

members = [{
        "member_id": 0,
        'title':  "Manager",
        'full_name': "John Doe",
        'first_name': None,
        'last_name': None,
        'age': 0,
},{
        "member_id": 1,
        'title':  " ",
        'full_name': "Jane Doe",
        'first_name': "Jane",
        'last_name': None,
        'age': 10,
}]

for member in members:
    toRemoveKeys = []

    for key, value in member.items():
        if value in (0, None, " "):
            toRemoveKeys.append(key)

    for key in toRemoveKeys:
        del member[key]

print(members)

Upvotes: 0

Related Questions