Filtering parent and children elements of list of dictionaries I have a list of dictionaries and its elements has id and parent_id fields.

Main purposes:


If the parent_id field of an element is defined, it should be returning the rest of elements except itself.
If the parent_id field of element is not defined, it should be returning the rest of elements. In other words, its all child elements. Because it is parent element.


I'll be sharing my implementation below. But I need more concise and Pythonic way.

products = [
    {"id": 5, "counter": 10, "parent_id": None},
    {"id": 6, "counter": 10, "parent_id": 5},
    {"id": 7, "counter": 10, "parent_id": 5},
]

def get_by_id(product_id):
    product = list(filter(lambda p: p["id"] == product_id, products))
    return product[0] if product else False

def get_by_product(product):
    p = []
    for i in products:
        if product["parent_id"]:
            if i["id"] == product["parent_id"] or i["id"] != product["id"]:
                p.append(i)
        else:
            if i["parent_id"] == product["id"]:
                p.append(i)
    return p

p = get_by_id(7)
g = get_by_product(p)
print(g) # [{'id': 5, 'counter': 10, 'parent_id': None}, {'id': 6, 'counter': 10, 'parent_id': 5}]

p = get_by_id(5)
g = get_by_product(p)
print(g) # [{'id': 6, 'counter': 10, 'parent_id': 5}, {'id': 7, 'counter': 10, 'parent_id': 5}]


I have changed ridiculous if statements above like this:

def get_by_product(product):
    p = []
    for i in products:
        if product["parent_id"] and i["id"] == product["parent_id"] or i["id"] != product["id"] or i["parent_id"] == product["id"]:
            p.append(i)
    return p
If your actual program has the products list is a constant global variable, declare it as PRODUCTS (uppercase global constants)
Using list(filter(lambda can be removed by a simple comprehension. A list comprehension is the preferred method of iterating over lists as per PEP-0202
Instead of returning False in get_by_id, return a None, as that is more user intuitive.


Check the following:

def get_by_id(product_id):
    """Return a product from the list with given id, or None if not found"""
    return next((p for p in PRODUCTS if p["id"] == product_id), None)


There is no extra list being created in-memory. The generator expression returns the first value (if any) or defaults to the None. Check docs for the next function.

For the get_by_product, you can have 2 snippets. One will remove the given product from list if product.parent_id exists, and another will search for child products.

def get_by_product(product):
    if product["parent_id"] is not None:
        return [p for p in PRODUCTS if p != product]
    return [p for p in PRODUCTS if p['parent_id'] == product['id']]