---
# System prepended metadata

title: Functional tools for nested data

---

#  Functional tools for nested data

- Build higher-order functions that operate on values stored in hash maps.
- Learn to easily operate on deeply nested data with higher-order functions.
- Understand recursion and how to do it safely.
- Understand when to apply abstraction barriers to deep, nested entities.

> We’ve been using higher-order functions and they’ve really helped clean up our code. We’re trying to modify the values that are nested inside an item object. We’ve got lots of operations that increment or decrement the size or the quantity. But somehow we can’t get past the duplication.

## Higher-order functions for values in objects

### Functions

```javascript=
function objectSet(object, key, value) {
  var copy = Object.assign({}, object);
  copy[key] = value
  return copy
}

function drop_first(array) {  
  var array_copy = array.slice()
  array_copy.shift()
  return array_copy
}

var shoes = {
  name: "shoes",
  quantity: 3,
  size: 1,
  price: 8
}
```

### Making the field name explicit

- Want to increase quantity or size of shoes.

![](https://i.imgur.com/InM4nhc.png)
![](https://i.imgur.com/CKtzfnO.png)
![](https://i.imgur.com/Zap1n0O.png)

### Deriving update()

- Remove that duplication and derive a functional tool that handles updating an object.

![](https://i.imgur.com/DEYdCh4.png)

- increase/decrease/double/halve are actions to operate value.
![](https://i.imgur.com/Uau7ROZ.png)

---

![](https://i.imgur.com/4ypSQvd.png)

```javascript
function divideBy2(price) {
    return price / 2;
}
```
We can apply this to the shops record using update(). We know that the price is located under the price key:

> update(shoes, 'price', divideBy2)

```javascript

{
  name: "shoes",
  quantity: 3,
  size: 1,
  price: 4 /* 8/2 */
}
```
---

![](https://i.imgur.com/4yhfZiU.png)

---

## Nested updates

```javascript=
var item = {
    name: 'shirt',
    price: 10,
    options: {
      color: 'red',
      size: 3,
    },
  },
}
```

- Want to increase size of shirt.

![](https://i.imgur.com/EZqGFTz.png)

![](https://i.imgur.com/ZjR1TZg.png)


### Deriving updateOption()

- We just wrote some code that did an update inside an update. We can generalize that operation to a function called update2():

![](https://i.imgur.com/nkmQuBl.png)

![](https://i.imgur.com/FISMYB7.png)

```javascript
function increment(size) {
    return size + 1;
}
```

> update2(item, 'options', 'size', increment)


### 3 level?

1. using update() and incrementSize()
2. using update() and update2()
3. using update()
4. writing it manually as gets, modify, and sets

### Deriving update3()

- update3() nests an update2() inside of an update().

![](https://i.imgur.com/kw3Bmjs.png)

### X level?

![](https://i.imgur.com/gyoITZn.png)


## The anatomy of safe recursion

1. Base case
2. Recursive case
3. Progress toward the base case

![](https://i.imgur.com/vUa8BT4.png)


### The superpower of recursion

![](https://i.imgur.com/pssR81U.png)
![](https://i.imgur.com/zUHi9ry.png)


### Design considerations with deep nesting

- Want to capitalize arthor's name.
- Hard to remember what keys you have.
- Chapter 9. When there is too much to think about, one way to address it is with an abstraction barrier.
- Abstraction barriers allow us to ignore details.

```javascript=

httpGet("http://my-blog.com/api/category/blog", function(blogCategory) {
  renderCategory(nestedUpdate(blogCategory, ['posts', '12', 'author', 'name'], capitalize));
});

var blogCategory = {
  posts: {
    12: {
      subject: '',
      body: '',
      arthor: {
        name: 'john wick',
      }
    }
  }
}

function objectSet(object, key, value) {
  var copy = Object.assign({}, object);
  copy[key] = value
  return copy
}

function drop_first(array) {  
  var array_copy = array.slice()
  array_copy.shift()
  return array_copy
}

function update(object, key, modify) {  
  var value = object[key];  
  var newValue = modify(value);  
  var newObject = objectSet(object, key, newValue);
  return newObject;
}

function nestedUpdate(object, keys, modify) {
	if(keys.length === 0)
	  return modify(object);
	
	var key1 = keys[0];
	var restOfKeys = drop_first(keys);
	return update(object, key1, function(value1) {
	  return nestedUpdate(value1, restOfKeys, modify);
	});
}

```

## Abstraction barriers on deeply nested data


```javascript

function updatePostById(category, id, modifyPost) {
    return nestedUpdate(category, ['posts', id], modifyPost);
}

function updateAuthor(post, modifyUser) {
  return update(post, 'author', modifyUser);
}

function capitalizeName(user) {
  return update(user, 'name', capitalize);
}

updatePostById(blogCategory, '12', function(post) {
  return updateAuthor(post, capitalizeUserName);
});
```

## Conclusion

- Learned how to apply the same refactorings to operations on nested data.
- Used recursion to work on data nested arbitrarily deep.
- Discussed the design implications of having such powerful operations on data and how to avoid the problems that power brings.

## Summary
- update() is a functional tool that implements a common pattern. It lets you modify a value inside of an object without manually pulling the value out and setting it back in.
- nestedUpdate() is a functional tool that operates on deeply nested data. It is very useful for modifying a value when you know the path of keys to where it is located.
- Iteration (loops) can often be clearer than recursion. But recursion is clearer and easier when operating on nested data.
- Recursion can use the function call stack to keep track of where it left off before calling itself. This lets a recursive function’s structure mirror the structure of nested data.
- Deep nesting can lead to difficulty of understanding. When you operate on deeply nested data, you often have to remember all of the data structures and their keys along the path.
- You can apply abstraction barriers to key data structures so that you don’t have as much to remember. This can make working with deep structures easier.