Skip to content

Instantly share code, notes, and snippets.

@MaraAlexa
Last active May 12, 2017 13:20
Show Gist options
  • Save MaraAlexa/f411cd6c9cea2daea6a9f6c3d89f45c1 to your computer and use it in GitHub Desktop.
Save MaraAlexa/f411cd6c9cea2daea6a9f6c3d89f45c1 to your computer and use it in GitHub Desktop.
Reduce Data with Array.reduce()
// 1. Transform a nested list into a single list = Flattten a list of lists
var data = [[1, 2, 3], [4, 5, 6], [7, 8]];
// flaten this array of arrays into a SINGLE array
var flattenedData = data.reduce(function(acc, value){
return acc.concat(value);
},[]);
console.log(flattenedData); // [1, 2, 3, 5, 6, 7, 8]
//_______________________________________________________________________________________________________
// 2. Flaten a list of complex objects => Real Case => Called a Flatmap
// a Flatmap takes in a list of items(values) and returns each of those values into an Array
var complexData = [
{
title: "Batman Begins",
year: 2005,
cast: [
"Michael Caine",
"Gary Oldman",
"Cillian Murphy"
]
},
{
title: "The Dark Knight",
year: 2008,
cast: [
"Michael Caine",
"Christian Bale",
"Morgan Freeman"
]
},
{
title: "The Dark Knight Rises",
year: 2012,
cast: [
"Christian Bale",
"Michael Caine"
]
}
];
// NAIVE way to get all the famous stars
var stars = input.reduce(function(acc, value){
return acc.concat(value.cast); // you get all the values from the cast including the repeated ones
},[]);
console.log(stars);
/* [
"Michael Caine",
"Gary Oldman",
"Cillian Murphy",
"Michael Caine",
"Christian Bale",
"Morgan Freeman",
"Christian Bale",
"Michael Caine"
] */
// SMART way: only include each star once
var stars = complexData.reduce(function(acc, value) {
value.cast.forEach(function(star) {
if (acc.indexOf(star) === -1) { // if the index of star does NOT EXist yet in the acc
acc.push(star); // push the star into the acc array
}
});
return acc;
}, []);
console.log(stars); // ["Michael Caine", "Gary Oldman", "Cillian Murphy", "Christian Bale", "Morgan Freeman"]
// Take an array and reduce it into a mean value
// mean = a number that represents the average value of a set of numbers => [1,2,3] = (1+2+3) / 3 = 2
// GOOD way - in 2 steps
var data = [1, 2, 3, 1];
// find the sum value
var sum = data.reduce(function(acc, value) {
return acc + value; // 0 + 1+2+3+1 = 7
}, 0);
// find the average value
var mean = sum / data.length; // 7 / 4 = 1.75
// ____________________________________________________________________________________
// BETTER way - in 1 step
// REDUCE always returns the last value of the iteration
// so before the last value is returned, we need to sneak in the / operation
var myMean = data.reduce(function(acc, value, index, array){
// need a var to hold the accumulated value up until the last value
var intermediaryValue = acc + value; // gives the intermidiary values for the accumulator 0 + 1+2+3= 6
// the logic to change the value of the last value returned (for the last iteration):
if(index === array.length - 1) { // if you are at the last item in the array
var lastValue = intermidiaryValue / array.length; // (acc + value) / 4 => (6+1) / 4 = 1.75
return lastValue; // 1.75
}
// if this is NOT the last iteration
// 1st : 0 + 1 = 1
// 2nd: 1 + 2 = 3
// 3rd: 3 + 3 = 6
// 4th: run IF case
return intermidiaryValue; // 6
}, 0)
console.log(myMean); // 1.75
// ---- * when you need a MODDIFIED ARRAY of the SAME LENGTH * ----
var data = [1, 2, 3];
// 1. with REDUCE
var doubled = data.reduce(function(acc, value) {
acc.push(value * 2);
return acc;
}, []);
console.log(doubled); // [2, 4, 6]
// 2. with MAP
var doubleMapped = data.map(function(item){
return item * 2;
})
console.log(doubleMapped); // [2, 4, 6]
// ---- * need a SHORTER ARRAY that contains some subset of those values (filter an array for something) * ----
var data2 = [1, 2, 3, 4, 5, 6];
// 1. with REDUCE
var even = data2.reduce(function(acc, item){
if(item % 2 === 0) {
acc.push(item);
}
return acc;
}, []);
console.log(even); // [2, 4, 6]
// 2. with FILTER
var evenFiltered = data2.filter(function(item){
return item % 2 === 0;
});
console.log(evenFiltered); // [2, 4, 6]
// ---------- * need to FILTER an array and MODIFY it * ----------
// 1. with FILTER and MAP ( you iterate 2 times)
var filterMapped = data2.filter(function(item) {
return item % 2 === 0; // [2, 4, 6]
}).map(function(item) {
return item * 2; // [4, 8, 12]
})
console.log(filterMapped); // [4, 8, 12]
// * ---- Use REDUCE to modify LARGE DATASETS * ----
// 2. with REDUCE (shorter time to run = good for big set of Data)- > iterate only once
var bigData = [1, 2, 3 ,4, ..., 999999, 1000000 ];
var reducedBigData = bigData.reduce(function(acc, item) {
if ( item % 2 === 0) {
acc.push(item * 2);
}
return acc;
}, []);
// Reduce an array into a single object -> {'angular': 3, 'react': 4, 'ember': 1. 'vanilla': 1}
var votes = [
"angular",
"angular",
"react",
"react",
"react",
"angular",
"ember",
"react",
"vanilla"
];
// ---- * you need AN OBJECT that gives the number of votes for each framework: 'angular': 2, 'react': 3 * ----
// in 2 Steps:
var initialValue = {}; // set up an empty obj as the initial value of the accumulator
var reducer = function(acc, vote){ // gets each vote one after another
if(!acc[vote]){ // if the key 'angular' does not yet exist in the accumulator obj
acc[vote]= 1; // then create a new key for the acc obj with 1 as its value; -> {'angular': 1}
} else {// if 'angular' already exists in the acc obj
acc[vote] = acc[vote] + 1; // increment its value ->'angular': 2
}
return acc; // VERY IMPORTANT
};
var result = votes.reduce(reducer, initialValue); //
// 1st->{};
// 2nd->{'angular': 1}
// 3rd->{'angular': 2};
// 4th->{'angular': 2, 'react': 1};
// 5th-> {'angular': 2, 'react': 2};
// 6th....etc...9th
console.log(result); // last iteration {'angular': 3, 'react': 4, 'ember': 1. 'vanilla': 1};
//_____________________________________________________________________________________________________________
// in 1 step: BETTER
var singleObj = votes.reduce(function(acc, vote){
// if the vote does not yet exist in the obj accumulator as a key property => 'angular' is not yet in the acc object
if(!acc[vote]) { // if key does Not yet exist; -> !acc['angular']
// create it as a new key property with 1 as its value;
acc[vote] = 1; // create new key: acc['angular'] = 1; => acc = {'angular': 1, ...}
}
else { // if the vote already exists as a key in the accumalator obj
acc[vote] = acc[vote] + 1; // increment its value: acc['angular'] = 2; => acc = {'angular': 2, ...}
}
return acc; // don't forget to return the object !! this runs for each item (vote) in the array
},{});
// Transform an Array of numbers into a SINGLE Value: [15, 3, 20] => 38
var data = [15, 3, 20];
// In 2 steps:
var reducer = function((accumulator, item) { // this func runs for each item in the array
return accumulator + item; // 15 + 3 + 20 = 38
}
var initialValue = 0; // you need an initial value for the accumulator
var total = data.reduce(reducer, initialValue); // how REDUCE works
// REDUCE returns only the last value of the accumulator
// the accumulator starts with 0 and adds up each value until the end of the array is reached
console.log("The sum is: ", total); // 38
// ____________________________________________________________________________________________________
// in 1 step:
var totalSum = data.reduce(function(acc, item){ // this loop runs for each item
return acc + item; // 0+15; 15+3; 18+20 => 38
},0); // 0 is the starting value of the acc needed for the first iteration; acc & item values change with each iteration
console.log(totalSum); // 38
@MaraAlexa
Copy link
Author

MaraAlexa commented May 11, 2017

## Different cases where you might use Array.prototype.reduce() to manipulate Arrays.

Also comparison doing the same manipulation: Array.prototype.filter() vs .filter() + .map()

IMPORTANT!!!
REDUCE has advantage over Filter + Map when using large data sets because with reduce you only iterate once over the data thus shorter run time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment