3.4. Pydash

Pydash is the kitchen sink of Python utility libraries for doing “stuff” in a functional way.

!pip install pydash 

3.4.1. Work with List

3.4.1.1. pydash.flatten: Flatten a Nested Python List

If you want to flatten a nested Python list, use the flatten method:

from pydash import py_

a = [[1, 2], [3, 4, 5]]
py_.flatten(a)
[1, 2, 3, 4, 5]

3.4.1.2. pydash.flatten_deep: Flatten a Deeply Nested Python List

If your list is deeply nested, use flatten_deep instead:

b = [[1, 2, [4, 5]], [6, 7]]
py_.flatten_deep(b)
[1, 2, 4, 5, 6, 7]

3.4.1.3. pydash.chunk: Split Elements into Groups

If you can flatten a list, can you also turn a flattened list into a nested one? Yes, that could be done with the chunk method:

a = [1, 2, 3, 4, 5]
py_.chunk(a, 2)
[[1, 2], [3, 4], [5]]

3.4.2. Work with Dictionary

3.4.2.1. Omit Dictionary’s Attribute

To omit an attribute from the dictionary, we can use the omit method:

fruits = {"name": "apple", "color": "red", "taste": "sweet"}
py_.omit(fruits, "name")
{'color': 'red', 'taste': 'sweet'}

3.4.2.2. Get Nested Dictionary’s Attribute

How do you get the price of an apple from Walmart that is in season in a nested dictionary like below?

apple = {
    "price": {
        "in_season": {"store": {"Walmart": [2, 4], "Aldi": 1}},
        "out_of_season": {"store": {"Walmart": [3, 5], "Aldi": 2}},
    }
}

Normally, you need to use a lot of brackets to get that information:

apple["price"]["in_season"]["store"]["Walmart"]
[2, 4]

Wouldn’t it be nice if you could use the dot notation instead of brackets? That could be done with the get method:

py_.get(apple, "price.in_season.store.Walmart")
[2, 4]

Cool! You can also get the element in an array using [index] :

py_.get(apple, "price.in_season.store.Walmart[0]")
2

3.4.3. Work with List of Dictionaries

3.4.3.1. Find Item Index Using a Function

list.index(element) allows you to get the index of the specified element in a list. However, you cannot get the index using a function.

fruits = [
    {"name": "apple", "price": 2},
    {"name": "orange", "price": 2},
    {"name": "grapes", "price": 4},
]
fruits.index({"name": "apple",  "price": 2})
0
filter_fruits = lambda fruit: fruit["name"] == "apple"

fruits.index(filter_fruits)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-8-b01bf8b7ae1a> in <module>
      1 filter_fruits = lambda fruit: fruit["name"] == "apple"
      2 
----> 3 fruits.index(filter_fruits)

ValueError: <function <lambda> at 0x7f9880491310> is not in list

To get the index of an element in a list using a function, use the find_index method instead:

py_.find_index(fruits, filter_fruits)
0

3.4.3.2. Find Objects With Matching Style

The find_index method allows you to get the index of the object that matches a certain pattern. But what if you want to get the items in a list instead of the index? That could be done with the filter method:

fruits = [
    {"name": "apple", "price": 2},
    {"name": "orange", "price": 2},
    {"name": "grapes", "price": 4},
]
py_.filter_(fruits, {"name": "apple"})
[{'name': 'apple', 'price': 2}]

3.4.3.3. Get Nested Object Value

Sometimes your list of dictionaries can be nested like below. How can you get the taste attribute of apple ?

fruits = [
    {"name": "apple", "attributes": {"color": "red", "taste": "sweet"}},
    {"name": "orange", "attributes": {"color": "orange", "taste": "sweet"}},
    {"name": "lemon", "attributes": {"color": "yellow", "taste": "sour"}},
]

Luckily, this can be easily done with the map_ method:

py_.map_(fruits, "attributes.taste")
['sweet', 'sweet', 'sour']

3.4.4. Work with Functions

3.4.4.1. Execute a Function n Times

You can execute a function n times using the times method. This method is a good alternative to a for loop.

py_.times(4, lambda: "I have just bought some apple")
['I have just bought some apple',
 'I have just bought some apple',
 'I have just bought some apple',
 'I have just bought some apple']
py_.times(4, lambda i: f"I have just bought {i} apple")
['I have just bought 0 apple',
 'I have just bought 1 apple',
 'I have just bought 2 apple',
 'I have just bought 3 apple']

3.4.5. Chaining

3.4.5.1. Pydash’s Methods

Sometimes you might want to apply several methods to an object. Instead of writing several lines of code, can you apply all methods at once?

That is when method chaining comes in handy. To apply method chaining in an object, use the chain method:

fruits = ["apple", "orange", "grapes"]
(py_.chain(fruits).without("grapes").reject(lambda fruit: fruit.startswith("a")))
<pydash.chaining.Chain at 0x7f027895d1f0>

Note that running the code above will not give us the value.

Only when we add .value() to the end of the chain, the final value is computed:

(
    py_.chain(fruits)
    .without("grapes")
    .reject(lambda fruit: fruit.startswith("a"))
    .value()
)
['orange']

This is called lazy evaluation. Lazy evaluation holds the evaluation of an expression until its value is needed, which avoids repeated evaluation.

3.4.5.2. Customized Methods

If you want to use your own methods instead of pydash’s methods, use the map method:

def get_price(fruit):
    prices = {"apple": 2, "orange": 2, "grapes": 4}
    return prices[fruit]
total_price = py_.chain(fruits).map(get_price).sum()
total_price.value()
8

3.4.5.3. Planting a Value

To replace the initial value of a chain with another value, use the plant method:

total_price.plant(["apple", "orange"]).value()
4

Cool! We replace ['apple', 'orange', 'grapes'] with ['apple', 'orange'] while using the same chain!