3
\$\begingroup\$

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 
\$\endgroup\$
  • 1
    \$\begingroup\$ How do you use these, because you could probably change the data to a dictionary for \$O(n)\$ creation, and \$O(1)\$ lookup, rather than \$O(n)\$ lookup. \$\endgroup\$ – Peilonrayz Jan 6 '18 at 4:07
  • \$\begingroup\$ It is not used in live environment. It was just a trivial code for practising. Open to any suggestions. \$\endgroup\$ – vildhjarta Jan 6 '18 at 13:26
3
\$\begingroup\$
  1. If your actual program has the products list is a constant global variable, declare it as PRODUCTS (uppercase global constants)
  2. 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
  3. 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']]
\$\endgroup\$
  • \$\begingroup\$ Do you have any source which explains the speed of list comprehensions over filter function? \$\endgroup\$ – vildhjarta Jan 6 '18 at 14:12
  • 1
    \$\begingroup\$ @vildhjarta stackoverflow.com/a/3013686/1190388 \$\endgroup\$ – hjpotter92 Jan 6 '18 at 14:25
  • \$\begingroup\$ if you add another product tree you can see the bug. if the product is not None, it returns all dictionaries except itself. \$\endgroup\$ – vildhjarta Jan 8 '18 at 20:39
  • 1
    \$\begingroup\$ You could simplify the get_by_id function, by using the default parameter to the next() function as specified here. return next((p for p in PRODUCTS if p["id"] == product_id), None) instead would be sufficient. \$\endgroup\$ – Jatimir Mar 18 '19 at 8:34
  • \$\begingroup\$ @Jatimir That is indeed better. Updated my code above. Thanks :) \$\endgroup\$ – hjpotter92 Mar 18 '19 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.