Part 1
Uh, that's how
not what
function mysteryOperation(nums) {
var i, sum = 0, squares = [];
for (i = 0; i < nums.length; i++) {
squares.push(nums[i]*nums[i]);
}
for (i = 0; i < squares.length; i++) {
sum += squares[i];
}
return sum;
}
console.log(
mysteryOperation( getArrayofIntegers() )
);
What does mysteryOperation do?
function mysteryOperation(nums) {
var i, sum = 0, squares = [];
for (i = 0; i < nums.length; i++) {
squares.push(nums[i]*nums[i]);
}
for (i = 0; i < squares.length; i++) {
sum += squares[i];
}
return sum;
}
console.log(
mysteryOperation( getArrayofIntegers() )
);
What does mysteryOperation do?
const mysteryOp = (nums) => nums
.map( (x) => x * x )
.reduce( (acc, c) => acc + c, 0);
in code -- what is how
Abstractly, it:
function mysteryOperation(nums) {
var i, sum = 0, tally = 0;
for (i = 0; i < nums.length; i++) {
if(nums[i]%2===0) {
sum += nums[i]/2
tally++;
}
}
return sum/tally;
}
What does this mysteryOperation do?
const isEven = (x) => x%2===0;
const half = (x) => x / 2;
const toAvg = (acc, c, i, arr) => (
i < arr.length - 1
? acc + c
: (acc + c) / arr.length
), 0)
const mysteryOperation = (nums) => nums
.filter( isEven )
.map( half )
.reduce( toAvg )
you know, from an abstract level
you know, from an abstract level
start
1
2
3
4
end
Examples:
state is data, event is data, it's all data
event + state
Examples:
aka: the effect
How, not What
so, between start & end, we can think of data streaming through a composition of transformative verbs. These verbs describe what those transformations do
start
1
2
3
4
end
start
1
2
3
4
end
a
b
c
end
start
1
2
3
4
end
a
b
i
ii
5
start
1
2
3
4
end
start
state
1
2
3
4
end
event
state
all the transformations in the middle can be represented with the verbs
are effectively mapped
follow some simple rules & best practices
(stateless, pure, no side-effects, etc)
and
become extremely reusable, easy to maintain, testable and have a simple mental model
& your app can scale horizontally
many functional libraries include these verbs
(map, filter, reduce, etc)
Observables / Rx.js turns ALL THE THINGS (that change over time) into things that can be mapped, filtered, reduced, concat, etc
bringing it back...
at a smaller scale
from endpoints, databases, etc
[...document.querySelectorAll('p')]
arrays in JavaScript have these verbs built in:
items.slice(0, 5)
Remove Items
items.concat([1, 2, 3])
Combine Items
items.concat(1)
items.concat([1, 2, 3])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.concat(11)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.concat([11, 12, 13, typeof window])
items.map(x => x * x)
Transform Each Item
[].map((x) => x * x)
Accepts a Lambda Function
lambda function accepts optional arguments 2 and 3, but they're less common
a higher-order function
[0, 1, 2, 3, 4, 5, 6, 7]
.map((x) => 2**x)
// [1, 2, 4, 8, 16, 32, 64, 128]
[
{w:10, h:20, d:10},
{w:3, h:2, d:20},
{w:4, h:1, d:400},
{w:9000, h:3999, d:9191}
].map( ({w, h, d}) => w * h * d)
// [2000, 120, 1600, 330793281000]
items.filter((x) => x%2===0)
Remove Items
Accepts a Lambda Function
lambda function accepts optional arguments 2 and 3, but they're less common
items.filter((x) => x%2===0)
a higher-order function
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.filter((x) => x%2 ===0 );
["bacon cheeseburger", "chicken sandwich", "hamburger", "bacon salad"]
.filter((x) => /bacon/i.test(x) );
items.reduce((acc, cur) => acc + cur, 0)
Transform From Array to Anything
array of blue circles
a red square
lambda function accepts optional arguments 3 and 4, but they're less common
Accepts a Lambda Function
Accepts an initial accumulation value
a higher-order function
items.reduce((acc, cur) => acc + cur, 0)
parity of "types" through each iteration
1
3
2
5
6
8
0
1
4
6
11
17
25
[1, 3, 2, 5, 6, 8].reduce(
(acc, cur) => acc + cur,
0
);
[ [1, 2, 3], [3, 2, 1], [5, 2, 1] ]
.reduce((acc, cur) => acc.concat(cur), [])
const splitEvery = (chunkSize, arr) => (
arr.reduce((acc, curr, i) => {
const index = Math.floor(i/chunkSize);
acc[index] = (acc[index]||[]).concat(curr);
return acc;
}, [])
);
const compose = (...fns) => (
(x) => fns.reduceRight(
(acc, curr) => curr(acc),
x
)
);
const curry = (fn) => (
(...args) => (
fn.length <=1 || args.length >= fn.length
? fn(...args)
: args.reduce( (acc, curr) => (
curry(acc.bind(null, curr)), fn)
)
)
);
const waterfall = (...promiseThunks) => (
() => promiseThunks.reduce(
(acc, curr) => acc.then( () => curr() ),
Promise.resolve()
)
)
[
{
key: "name", value: "jared"
},
{
key: "age", value: "old",
},
{
key: "food", value: "bacon"
},
{
key: "kids", value: "gazillions"
},
{
key: "garbageA", value: "valueA"
},
{
key: "garbageB", value: "valueB"
}
]
{
name: "jared",
age: "old",
food: "bacon",
kids: "gazillions"
}
From this Shape
To this Shape
without
"garbage"
const endShape = startShape
.filter(({key}) => key.indexOf("garbage")===-1)
.map( ({key, value}) => ({[key]: value}) )
.reduce((acc, curr) => ({...acc, ...curr}), {})
[
{
key: "name", value: "jared"
},
{
key: "age", value: "old",
},
{
key: "food", value: "bacon"
},
{
key: "food", value: "pizza"
},
{
key: "food", value: "cubby's"
},
{
key: "food", value: "wings"
},
{
key: "food", value: "shakes"
}
];
{
age: "old",
kids: "gazillions",
name: "jared",
food: [
"bacon",
"pizza",
"cubby's",
"wings",
"shakes"
]
}
From this Shape
To this Shape
startShape
.map(({key, value}) => ({[key]: value}))
.reduce((acc, curr) => {
const key = Object.keys(curr)[0];
return {
...acc,
[key]: acc[key]
? [].concat( acc[key] ).concat( curr[key] )
: curr[key]
};
}, {})
Write a function which takes an array of any depth (nested) and returns a completely flattened array
Part 2