It's about to go down
Time to practice thinking and building like a true Software Engineer
OverView
-
Advanced Algorithmic Approach
-
Intermediate HOF #1
-
Building Your Tool Belt
-
Intermediate HOF #2
algorithmic approach
How to approach any software engineering problem
-
Data Modeling
-
Function Modeling
-
Pseudo Coding
-
Choosing your tools
OverView
Loop & Transform
loop = function(collection, callback){
if (Array.isArray(collection)){
for (var i = 0; i < collection.length; i++){
callback(collection[i], i);
}
} else if (typeof collection === 'object'){
for (var key in collection){
callback(collection[key], key);
}
}
};
transform = function(collection, callback){
var results = [];
loop(collection, function(element){
results.push(callback(element));
});
return results;
};
In week 3 we focused on these two functions
Loop and transform allow us to write concise and elegant code.
var friends = ['Kmack', 'Jon', 'Albrey'];
loop(friends, function(friend){
console.log(friend + ' is my friend :)');
};
// Kmack is my friend :)
// Jon is my friend :)
// Albrey is my friend :)
var enemies = transform(friends, function(friend){
return {
name: friend,
evil: true,
};
});
console.log(enemies)
// [{name: 'Kmack', evil: true}, {name: 'Jon', evil: true}..]
They are the tools and our toolbelts that get rid of clutter and confusion.
Loop & Transform
At this point, we know how to use these tools to build software
var friends = ['Kmack', 'Jon', 'Albrey'];
loop(friends, function(friend){
console.log(friend + ' is my friend :)');
};
// Kmack is my friend :)
// Jon is my friend :)
// Albrey is my friend :)
var enemies = transform(friends, function(friend){
return {
name: friend,
evil: true,
};
});
console.log(enemies)
// [{name: 'Kmack', evil: true}, {name: 'Jon', evil: true}..]
A necessary skill is to figure out when it's best to use these tools.
Let's move away from sample problems and work on a real world example
Contract Work
Work Work Work Work Work
A client comes to us and says, "My store has been miscalculating transactions since opening back in February; each of our 19,284 transactions are not processed to include the .09% California state tax. I have a list containing the price of each transaction.
Can you build me software that will give me a list of each individual transaction calculated with the state tax."
The Problem
Break It down now
What they have: a list of prices.
What they need: a new list of prices + tax.
First we identify our inputs and outputs.
inputs: a list of prices.
outputs: a new list of prices + tax.
Break It down now
Model our input data.
inputs: a list of prices.
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
Our users data is pretty straight forward
Most of the time it won't be this easy.
Break It down now
Mock test our function
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
// input, array full of integers
var samplePricesWithTax = includetax(samplePrices);
console.log(samplePricesWithTax);
// expected output tested by human test
// [31.61, 63.22, 18.53, 151.51, 101.37...]
inputs: a list of prices.
outputs: a new list of prices + tax.
Break It down now
Psuedocode it out
// go through a list of prices
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
Pseudocode should be a good mix of english and engineering language.
You can see it as a way to outline your function before building it.
Break It down now
Choose Your Tools
// go through a list of prices
//calculate each price plus the tax
// gather the list of new prices
// return it to the user
Let’s look at our tool belt and see what we should use for this:
Loop: Loops through a collection & performs some sort of action on each item, index, or the collection itself.
Transform: Loops through a collection & performs some sort of transformative action on each element, and returns anarray containing each transformed element.:
Break It down now
Let's Build It
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var includeTax = function(listOfPrices){
// go through a list of prices
//calculate each price plus the tax
// gather the list of new prices
// return it to the user
};
Add your pseudocode to the inside of your function
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var includeTax = function(listOfPrices){
// go through a list of prices
return transform(listOfPrices, function(price){
// calculate each price plus the tax
// gather the list of new price
return (price * 0.09) + price;
});
// return the new array to the user
};
Build our function according to our pseudocode
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var includeTax = function(listOfPrices){
// go through a list of prices
return transform(listOfPrices, function(price){
// calculate each price plus the tax
// gather the list of new price
return (price * 0.09) + price;
});
// return the new array to the user
};
var samplePricesWithTax = includeTax(samplePrices);
// [31.61, 63.22, 18.53, 151.51, 101.37, 14.17, 534.1, 10.9]
Test our function using our samplePrices
Takeaways
That was pretty straight forward right?
Steps Taken
- Assessed the problem
- Figured out our inputs and outputs
- Modeled our Data
- Made a plan (pseudocode)
- Chose our tool (transform)
Great - Let's try another one!
Contract Work 2
Work Work Work Work Work
Our client comes back to us and asks us again whether we can build a piece of software that will add the tax to the prices. But this time, they only want to add the tax to prices over 50.
The Problem
Break It down now
What they have: a list of prices.
What they need: a new list of prices + tax.
First we identify our inputs an outputs.
inputs: a list of prices.
outputs: a new list of prices + tax.
CONDITION: THE NEW LIST ONLY CONTAINS PRICES OVER 50
Break It down now
Model our input data.
inputs: a list of prices.
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
Our users data doesn't change.
Break It down now
Mock test our function
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
// input, array full of integers
var samplePricesWithTax = overFiftyTax(samplePrices);
console.log(samplePricesWithTax);
// expected output tested by human test
// [63.22, 151.51, 101.37, 534.1]
inputs: a list of prices.
outputs: a new list of over 50 prices + tax
Break It down now
Psuedocode it out
// go through a list of prices
// check if price is over 50
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
Break It down now
Choose Your Tools
// go through a list of prices
// check if price is over 50
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
Let’s look at our tool belt and see what we should use for this:
Loop: Loops through a collection & performs some sort of action on each item, index, or the collection itself.
Transform: Loops through a collection & performs some sort of transformative action on each element, and returns anarray containing each transformed element.:
Break It down now
Let's Build It
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
// check if price is over 50
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
transform(listOfPrices, function(price){
// check if price is over 50
});
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
transform(listOfPrices, function(price){
// check if price is over 50
if (price > 50){
// calculate each price plus the tax
// add to the new list of new prices
return price + (price * 0.09);
}
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
return transform(listOfPrices, function(price){
// check if price is over 50
if (price > 50){
// calculate each price plus the tax
// add to the new list of new prices
return price + (price * 0.09);
}
});
// return new list of prices to user
};
Add your pseudocode to the inside of your function
Add our transform function
Sprinkle in a conditional
Make sure to return to our user
Test the end product
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
return transform(listOfPrices, function(price){
if (price > 50){
return price + (price * 0.09);
}
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
return transform(listOfPrices, function(price){
if (price > 50){
return price + (price * 0.09);
}
});
};
var samplePricesWithTax = overFiftyTax(samplePrices);
console.log(samplePricesWithTax);
// [undefined, 63.22, undefined, 151.51, 101.37, undefined..];
Break It down now
overFiftyTax in depth
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
return transform(listOfPrices, function(price){
if (price > 50){
return price + (price * 0.09);
}
});
};
var samplePricesWithTax = overFiftyTax(samplePrices);
console.log(samplePricesWithTax);
// [undefined, 63.22, undefined, 151.51, 101.37, undefined..];
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
console.log("initializing transform function");
return transform(listOfPrices, function(price){
console.log(" current price is:", price);
if (price > 50){
console.log("price is over 50, returning new price");
return price + (price * 0.09);
}
console.log("not going through if, still returning");
});
};
var samplePricesWithTax = overFiftyTax(samplePrices);
How can we debug this?
Let's throw some console.logs in there
Break It down now
explanation
Transform does go through the collection and collect each element, but it can not choose which elements to collect.
Transform is not the right tool.
Let's try loop!
Break It down now
overFiftyTax with loop
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
// check if price is over 50
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
loop(listOfPrices, function(price){
// check if price is over 50
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
loop(listOfPrices, function(price){
if (price > 50) {
// calculate each price plus the tax
// gather the list of new prices
// return it to the user
}
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
// go through a list of prices
loop(listOfPrices, function(price){
if (price > 50) {
// calculate each price plus the tax
var newPrice = price + (price * 0.09)
// gather the list of new prices
// return it to the user
}
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
var result = [];
// go through a list of prices
loop(listOfPrices, function(price){
if (price > 50) {
// calculate each price plus the tax
var newPrice = price + (price * 0.09)
// gather the list of new prices
result.push(newPrice)
// return it to the user
}
});
};
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
var result = [];
// go through a list of prices
loop(listOfPrices, function(price){
if (price > 50) {
// calculate each price plus the tax
var newPrice = price + (price * 0.09)
// gather the list of new prices
result.push(newPrice)
}
});
// return it to the user
return result;
};
Let's test it
Break It down now
testing overFiftyTax with loop
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
var result = [];
loop(listOfPrices, function(price){
if (price > 50) {
var newPrice = price + (price * 0.09)
result.push(newPrice)
}
});
return result;
};
var samplePricesWithTax = overFiftyTax(samplePrices);
console.log(samplePricesWithTax);
// [63.22, 151.51, 101.37, 534.1]
var samplePrices = [29, 58, 17, 139, 93, 13, 490, 10];
var overFiftyTax = function(listOfPrices){
var result = [];
loop(listOfPrices, function(price){
if (price > 50) {
var newPrice = price + (price * 0.09)
result.push(newPrice)
}
});
return result;
};
var samplePricesWithTax = overFiftyTax(samplePrices);
console.log(samplePricesWithTax);
Takeaways
Steps Taken
- Assessed the problem
- Figured out our inputs and outputs
- Modeled our Data
- Made a plan (pseudocode)
- Chose our tool (transform)
- Chose the wrong tool
- Went back and built something new for our specific need
Sometimes it's going to be difficult to figure out which tool you need from the onset.
It is important to keep in mind the exact purpose of your function before choosing to build with it.
Exercises
https://github.com/TelegraphPrep/CarFaxDotCom
Understanding
Distill
Overview:
- What distill does
- Build distill
- Learn how to use distill
Functions We Covered:
- loop
- can be used to iterate through collections (side effect)
- transform
- used to change values in a collection and produce a new array (returning a value)
- filterBy
- predicate determines if the elements within the collection will changed and/or be return in a new array
What the __ is distill?
var numbers = [59, 72, 21, 16]
var sumOfNumber = distill(numbers, function(sum, currentNumber){
return sum + currentNumber;
}, 0);
console.log(sumOfNumbers) // 168
** Notice that the value is not returned in an array...
Lets Build distill
//distill takes a collection, a callback, and a startValue.
//iterates through the collection and on each iteration updates the startValue to
//whatever the callback evaluates to.
// After iterating through the collection it returns the updated startValue to the user.
Lets write in plain english the functionality of distill
Lets Build distill
// distill takes a collection, a callback, and a startValue.
var distill = function(collection, callback, startValue){
startValue = startValue || 0;
//iterates through the collection and on each iteration updates the startValue to
//whatever the callback evaluates to.
loop(collection, function(element){
startValue = callback(startValue, element, index);
});
// After iterating through the collection it returns the updated startValue to the user.
return startValue;
}
Lets write in plain english the functionality of distill
Drop down and Get your distill on..
var numbers = [1, 2, 3];
distill(numbers, function(previousValue, currentValue, index){
console.log(previousValue, currentValue, index);
return previousValue + currentValue;
});
// This is logged to our console:
// 0 1 0 previousValue: 0 currentValue: 1 index: 0
// 1 2 1 previousValue: 1 currentValue: 2 index: 1
// 3 3 2 previousValue: 3 currentValue: 3 index: 2
// 6 previousValue: 6
Lets practice using distill and dig deeper into distillation
Drop down and Get your distill on..
var numbers = [1, 2, 3];
distill(numbers, function(previousValue, currentValue, index){
console.log(previousValue, currentValue, index);
return previousValue + currentValue;
}, 100);
// This is logged to our console:
// 100 1 0 previousValue: 100 currentValue: 1 index: 0
// 101 2 1 previousValue: 101 currentValue: 2 index: 1
// 103 3 2 previousValue: 103 currentValue: 3 index: 2
// 106 previousValue: 106
Lets practice using distill and dig deeper into distillation
Contract Work
Another day, another dollar...
Sony contacted us about a project. They would like you to parse through iTunes sales for the top 5 albums of March and get the total albums sales on iTunes from those top 5 albums.
Modeling Our Data
Input: Array
Output: Interger
Lets get this Check!
// Their data is stored in an object like this:
var topFiveAlbums = [
{
title: "Purple Rain",
author: "Prince",
sales: 1000000
},
{
title: "Life of Pablo",
author: "Kanye West",
sales: 250000
},
{
title: "Reflektor",
author: "Arcade Fire",
sales: 150000
},
{
title: "25",
author: "Adele",
sales: 1000000
},
{
title: "Anti",
author: "Bad Gal RiRi",
sales: 500000
}
];
Lets get this Check!
// Get an array of sales values only
var arrayOfSales = transForm(topFiveAlbums, function(albums) {
return albums.sales;
});
console.log(arrayOfSales) // [10000, 250000, 150000, 1000000, 500000];
// Condense the array's values from left to right
var totalSales = distill(arraysOfSales, function(prev, curr) {
return prev + curr;
});
console.log(totalSales) // 1,901,000
// prev: 0 curr: 10000
// prev: 10000 curr: 250000
// prev: 251000 curr: 150000
// prev: 401000 curr: 1000000
// prev: 1410000 curr: 500000
// prev: 1,901,000
The Real Distill.
var distill = function(collection, callback, startValue){
startValue = startValue || 0;
loop(collection, function(element){
startValue = callback(startValue, element, index);
});
return startValue;
};
Review our current version of distill:
The Real Distill.
// distill takes a collection, a callback, and a startValue.
//if the start value is not given
//if the collection is an array,
// remove the first value in the array and use that first value
// in the array as the startValue
//iterates through the collection and on each iteration updates the startValue
// to whatever the callback evaluates to.
// After iterating through the collection it returns the updated startValue to the user.
The Real Distill.
// distill takes a collection, a callback, and a startValue
var distill = function(collection, callback, startValue){
//if the start value is not given
//if the collection is an array,
// remove the first value in the array and use that first value
// in the array as the startValue
startValue = startValue || null
if(startValue === null){
if(Array.isArray(collection)){
startValue = collection.shift();
}
}
//iterates through the collection and on each iteration updates the startValue
// to whatever the callback evaluates to.
loop(collection, function(element, index){
startValue = callback(startValue, element, index);
})
// After iterating through the collection it returns the updated startValue to the user.
return startValue;
};
The Real Distill.
var numbers = [1, 2, 3];
distill(numbers, function(prev, curr, index){
console.log(prev, curr, index);
return prev + curr;
});
// This logs:
// 1 2 0
// 3 3 1
// 6
// As you can see, the callback actually didn't iterate over the first element of the array.
// Instead, prev was set to the value of the first element. It has to work that way because
// otherwise distill wouldn't have a starting value for prev.
// The function ran three times, but on the last call, it wasn't given a current
// element since there were no elements left in the array.
The Real Distill.
// Here is another example:
var numbers = [1, 2, 3];
distill(collection, function(prev, curr, index) {
console.log(prev, curr, index);
return prev + curr;
}, 100);
// Outputs:
// 100 1 0
// 101 2 1
// 103 3 2
// 106
// In addition to the callback function, we also passed in an starting value for prev.
// You see that the callback did iterate over the first element in the array,
// since it had an initial value to work with.
The Real Distill.
// distill only good for working with integers? Whatttt? Nah. Check this out:
var relationashipArray = [
["Kmack", "Jon"],
["Jon", "Albrey"],
["Albrey", "Bianca"]
];
var relationshipMap = distill(relationshipArray, function(prev, curr) {
prev[curr[0]] = curr[1];
return prev;
}, {});
console.log(relationshipMap);
// Outputs:
// {
// "Kmack": "Jon",
// "Jon": "Albrey",
// "Albrey": "Bianca"
// }
// We used distill to transform our relationship array from an array of arrays into
// an object where each key value pair describes the relationship.
Time to practice
https://github.com/TelegraphPrep/BookstoreApplication
It's About To Go Down
By telegraphprep
It's About To Go Down
Upping the Ante at Telegraph Prep+
- 1,360