Last active
August 29, 2015 14:21
-
-
Save localshred/35db417a6d4ba1fe19fe to your computer and use it in GitHub Desktop.
Handling lists with higher-order functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "awesome_print" | |
## | |
# The term "higher-order" is meant to describe a function that | |
# takes other functions as arguments, produces a function as a return value, | |
# or both. | |
# | |
# ----> tl;dr use higher-order functions for working with lists as opposed to general "for loop" iteration. | |
# | |
# See also: | |
# + Ruby Enumerable: http://ruby-doc.org/core-2.2.2/Enumerable.html | |
# + JS Array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array (note “experimental” icon next to es6 methods) | |
# + C# Linq Enumerable: https://msdn.microsoft.com/en-us/library/system.linq.enumerable(v=vs.111).aspx | |
A_HASH = { | |
:a => 1, | |
:b => 2, | |
:c => 3 | |
} | |
PRIMES = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ] | |
################################ | |
## | |
## EACH : | |
## Input: An Enumerable | |
## Ouput: return value of last block invocation (don't use) | |
## | |
## Iterate through a list or hash, yielding each element | |
## to the block. | |
## | |
## Generally useful for side-effect operations (e.g. logging) | |
## | |
## Replaces general for loops. | |
## | |
################################ | |
# "Old" way | |
# | |
# for (var i = 0; i < PRIMES.length; i++) do | |
# puts "I'm a prime!: #{PRIMES[i]}" | |
# end | |
# "New" way | |
PRIMES.each do |prime| | |
puts "I'm a prime!: #{prime}" | |
end | |
A_HASH.each_pair do |key, value| | |
puts "#{key} => #{value}" | |
end | |
################################ | |
## | |
## MAP : | |
## Turn an a list of apples into oranges | |
## | |
## Input: An Enumerable | |
## Ouput: A different Enumerable of same size | |
## | |
## Iterates over a list, yielding each element to the block, | |
## and builds a new list out of the returned elements from the block | |
## | |
## Replaces initializing a new list, iterating some other list and pushing | |
## to the new list. | |
## | |
################################ | |
# Old Way | |
squared_primes = [] | |
PRIMES.each do |v| | |
squared_primes.push(v ** 2) | |
end | |
# New way | |
puts "Squared Primes" | |
squared_primes = PRIMES.map do |v| | |
v ** 2 | |
end | |
ap(squared_primes) | |
fizzbuzz = (1..20).map do |i| | |
case | |
when i % 3 == 0 then "Fizz" | |
when i % 5 == 0 then "Buzz" | |
else i.to_s | |
end | |
end | |
puts "FizzBuzz" | |
ap(fizzbuzz) | |
################################ | |
## | |
## SELECT : | |
## Find elements in a list that match some condition | |
## | |
## Input: An Enumerable | |
## Ouput: A sub-selection of items from the input, possibly an empty array. | |
## | |
## Iterates over a list, yielding each element to the block, | |
## and returns the elements for which the block returned a truthy value | |
## | |
## Replaces general loops with if/else/case statements in them. | |
## | |
################################ | |
# Old way | |
evens = [] | |
odds = [] | |
(1..10).each do |v| | |
if v.odd? | |
odds.push(v) | |
else | |
evens.push(v) | |
end | |
end | |
# New way | |
range = (1..10) | |
evens = range.select { |v| v.even? } | |
odds = range.select { |v| v.odd? } | |
# or use Symbol#to_proc | |
evens = range.select(&:even?) | |
odds = range.select(&:odd?) | |
# Variant "any?" or "all"? | |
has_any_evens = false | |
range.each do |v| | |
if v.even? | |
has_any_evens = true | |
break | |
end | |
end | |
# or using Symbol#to_proc | |
has_any_evens = range.any?(&:even?) | |
are_all_even = range.all?(&:even?) | |
################################ | |
## | |
## DETECT : | |
## Find ONE element in a list that matches some condition | |
## | |
## Input: An Enumerable | |
## Ouput: A single item from the input, or nil. | |
## | |
## Iterates over a list, yielding each element to the block, | |
## and returns the first element where the block returns truthy. | |
## | |
## Replaces general loops with if/else/case statements in them that | |
## intend to "Find" a single value in the array by some check. | |
## | |
################################ | |
# Old way | |
value = nil | |
(1..10).each do |v| | |
if v * 10 == 100 | |
value = v | |
break | |
end | |
end | |
# New way | |
value = (1..10).detect do |v| | |
(v * 10) == 100 | |
end | |
################################ | |
## | |
## REDUCE : | |
## Turn a list into any other kind of data type. | |
## | |
## Input: An Enumerable and an optional start value. | |
## Ouput: An object that was accumulated through all iterations. | |
## | |
## Iterates over a list with a start value of some kind (list, hash, number, etc), | |
## yielding the accumulated value _and_ each element to the block. | |
## The return value of the block becomes the accumulator for the first argument | |
## to the block in the next invocation. | |
## The final return value of the block determines the reduce function's return value. | |
## | |
## Replaces general loops that attempt to build an object from some list of values. | |
## | |
################################ | |
# Old way | |
sum = 0 | |
PRIMES.each do |prime| | |
sum += prime | |
end | |
ap(sum) | |
# New way | |
sum = PRIMES.reduce({}) do |accumulator, prime| | |
accumulator[prime] = prime ** 2 | |
accumulator | |
end | |
ap(sum) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment