# Reducing Enumerable — No-Op and Boolean

### Recap

So in the previous post, we took a look at a few basic Enumerable functions made in terms of reduce

For reference, those were:

Map

`def map(list, &fn)  list.reduce([]) { |a, i| a.push(fn[i]) }end`
`map([1,2,3]) { |i| i * 2 }# => [2, 4, 6]`

Select

`def select(list, &fn)  list.reduce([]) { |a, i| fn[i] ? a.push(i) : a }end`
`select([1,2,3]) { |i| i > 1 }# => [2, 3]`

Find

`def find(list, &fn)  list.reduce(nil) { |_, i| break i if fn[i] }end`
`find([1,2,3]) { |i| i == 2 }# => 2`
`find([1,2,3]) { |i| i == 4 }# => nil`

In these cases we’ve been reducing onto arrays or just flat out ignoring the reducing value.

One should pay special attention to the fact that we’re ignoring the accumulator, because this yields a very interesting observation about the behavior of reduce.

### What are we covering this time?

This round will cover no-op and boolean functions of Enumerable.

### No-Op Functions

Find only happened to do something with no accumulator because of break, but reduce can be used for no-op functions as well, like each:

`def each(list, &fn)  list.reduce(nil) { |_, i| fn[i] }  listend`

While not technically an Enumerable function, it’s the base of everything else under it. That said, our implementation doesn’t satisfy that constraint.

### Boolean Functions

One of the fun things you can do is reduce into a boolean or even bitwise operation.

Functions that do this are ones like: `any?, all?, none?, one?, include?, member?`

Let’s take a look at a few of them:

any?

`def any?(list, &fn)  list.reduce(false) { |_, i|    break true if fn[i]    false  }end`
`any?([1,2,3]) { |i| i > 5 }# => false`
`any?([1,2,3]) { |i| i > 1 }# => true`

The caveat here is that break does not play nicely with ternaries, and `if x then` just doesn’t feel quite right.

Like `find` , `any?` will break early if it finds something.

Granted this could be simplified with a `!!` to a one-liner, but I’m going to err on the side of verbosity for these posts:

`def any?(list, &fn)  !!list.reduce(nil) { |_, i| break true if fn[i] }end`

all?

`def all?(list, &fn)  list.reduce(true) { |a, i| a && fn[i] }end`
`all?([1,2,3]) { |i| i > 0 }# => true`
`all?([1,2,3]) { |i| i > 2 }# => false`

`all?` introduces us to folding using `&&` and a boolean value. The idea here is to see if all elements match the predicate function. That said, this first implementation doesn’t quite get there. Can you see what’s wrong with it?

What happens if any one of the elements is false? It should probably break out early like our other functions:

`def all?(list, &fn)  list.reduce(true) { |a, i|    break false unless fn[i]    true  }end`
`all?([1,2,3]) { |i| i > 0 }# => true`
`all?([1,2,3]) { |i| i > 2 }# => false`

none?

`none?` is basically the inverse of `any?` . If we really wanted to we could define it in terms of `any?` :

`def none?(list, &fn)  !any?(list, &fn)end`
`none?([1,2,3]) { |i| i > 2 }# => false`
`none?([1,2,3]) { |i| i > 5 }# => true`

Ideally we should reuse what we already have, but the point of this series is to go through how you’d implement things in terms of reduce:

`def none?(list, &fn)  list.reduce(false) { |_, i|    break false if fn[i]    true  }end`
`none?([1,2,3]) { |i| i > 2 }# => false`
`none?([1,2,3]) { |i| i > 5 }# => true`

Basically you just end up with the conditions switches and voilá!

one?

`def one?(list, &fn)  list.reduce(false) { |a, i|    if fn[i]      break false if a      true    else      a    end  }end`
`one?([1,2,3]) { |i| i == 2 }# => true`
`one?([1,2,3]) { |i| i > 1 }# => false`
`one?([1,2,3]) { |i| i > 5 }# => false`

`one?` has the added bonus of having to make sure we get, well, one match. Now we not only have to check if the functional predicate was true, but also that it wasn’t true before now.

Because of the way this works, we can’t break out in all cases, only those in which we had more than one occurrence. Now we could have reduced onto an integer and ran a count of occurrences, but we already have a boolean status we may as well use!

include? and member?

`def include?(list, item)  list.reduce(false) { |a, i|    break true if i == item    false  }end`
`include?([1,2,3], 1)# => true`
`include?([1,2,3], 5)# => false`

`include?` and `member?` are the same, so we’ll just group them both under this branch.

Much like find, it only has to find one item or return false otherwise.

### Wrapping Up

Next time we’re going to start covering functions deal with Integer state like `min` and `max` and sorting.

Like what you read? Give Brandon Weaver a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.