Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
"no-useless-constructor": 0,
"import/no-unresolved": 0
}
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
*.swp
node_modules
package-lock.json
*yarn*
62 changes: 57 additions & 5 deletions src/arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,89 @@ const each = (elements, cb) => {
// This only needs to work with arrays.
// You should also pass the index into `cb` as the second argument
// based off http://underscorejs.org/#each
for (let i = 0; i < elements.length; i++) {
cb(elements[i], i);
}
};

const map = (elements, cb) => {
// Produces a new array of values by mapping each value in list through a transformation function (iteratee).
// Return the new array.
};

const reduce = (elements, cb, startingValue) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also do this for a starting value: (elements, cb, startingValue = elements.shift()) for the default value. This takes advantage of the ES6 default parameters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless of course you are avoiding modifying the input array

// Combine all elements into a single value going from left to right.
// Elements will be passed one by one into `cb`.
// `startingValue` is the starting value. If `startingValue` is undefined then make `elements[0]` the initial value.
let i = 0;
if (startingValue === undefined) {
startingValue = elements[0];
i = 1;
}
let acc = startingValue;
for (; i < elements.length; i++) {
acc = cb(acc, elements[i], i);
}
return acc;
};

const map = (elements, cb) => {
// Produces a new array of values by mapping each value in list through a transformation function (iteratee).
// Return the new array.
return reduce(elements, (acc, v) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really creative

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

acc.push(cb(v));
return acc;
}, []);
};

const find = (elements, cb) => {
// Look through each value in `elements` and pass each element to `cb`.
// If `cb` returns `true` then return that element.
// Return `undefined` if no elements pass the truth test.
for (let i = 0; i < elements.length; i++) {
if (cb(elements[i])) {
return elements[i];
}
}
return undefined;
};

const filter = (elements, cb) => {
// Similar to `find` but you will return an array of all elements that passed the truth test
// Return an empty array if no elements pass the truth test
return reduce(elements, (acc, v) => {
if (cb(v)) {
acc.push(v);
}
return acc;
}, []);
};

/* Extra Credit */

const isArray = (elements) => {
return Array.isArray(elements);
};
const flatten = (elements) => {
// Flattens a nested array (the nesting can be to any depth).
// Example: flatten([1, [2], [3, [[4]]]]); => [1, 2, 3, 4];
if (!isArray(elements)) {
return elements;
}
while (elements.length === 1 && Array.isArray(elements[0])) {
elements = elements[0];
}
let r = [];
r.push(flatten(elements[0]));
let next = elements.slice(1);
while (next.length === 1 && Array.isArray(next[0])) {
next = next[0];
}
if (next.length > 0) {
while (r.length === 1 && Array.isArray(r[0])) {
r = r[0];
}
r = r.concat(flatten(next));
}
return r;
};


/* eslint-enable no-unused-vars, max-len */

module.exports = {
Expand Down
34 changes: 27 additions & 7 deletions src/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,57 +25,77 @@

const foods = ['pineapple', 'mango', 'ribeye', 'curry', 'tacos', 'ribeye', 'mango'];

function firstItem(foods, f) {
return f(foods[0]);
}

firstItem(foods, (firstItem) => {
console.log(`The first item is ${firstItem}.`);
});

// Write a function called getLength that passes the length of the array into the callback
// code here

function getLength(foods, f) {
return f(foods.length);
}
getLength(foods, (length) => {
console.log(`The length of the array is ${length}.`);
});

// Write a function called last which passes the last item of the array into the callback
// code here

function last(foods, f) {
return f(foods[foods.length -1]);
}
last(foods, (lastItem) => {
console.log(`The last item in the array is ${lastItem}.`);
});

// Write a function called sumNums that adds two numbers and passes the result to the callback
// code here

function sumNums(x, y, f) {
return f(x + y)
}
sumNums(5, 10, (sum) => {
console.log(`The sum is ${sum}.`);
});

// Write a function called multiplyNums that adds two numbers and passes the result to the callback
// code here

function multiplyNums(x, y, f) {
return f(x * y);
}
multiplyNums(5, 10, (product) => {
console.log(`The product is ${product}.`);
});

// Write a function called contains that checks if an item is present inside of the given array.
// Pass true to the callback if it is, otherwise pass false
// code here

function contains(foods, item, f) {
return f(foods.indexOf(item) >= 0)
}
contains(foods, 'ribeye', (result) => {
console.log(result ? 'ribeye is in the array' : 'ribeye is not in the array');
});

// Write a function called removeDuplicates that removes all duplicate values from the given array.
// Pass the array to the callback function. Do not mutate the original array.
// code here

function removeDuplicates(foods, f) {
f(foods.filter((food,i) => {
return foods.indexOf(food) === i;
}))
}
removeDuplicates(foods, (uniqueFoods) => {
console.log(`foods with duplicates removed: ${uniqueFoods}`);
});

// Write a function called forEach that iterates over the provided array and passes the value and index into the callback.
// code here

function forEach(foods, f) {
return foods.forEach((food,i) => f(food,i));
}
forEach(foods, (value, index) => {
console.log(`${value} is at index ${index}.`);
});
Expand Down
33 changes: 33 additions & 0 deletions src/closure.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,39 @@ const counter = () => {
// Example: const newCounter = counter();
// newCounter(); // 1
// newCounter(); // 2
let localCounter = 0;
return () => {
return ++localCounter;
};
};

const counterFactory = () => {
// Return an object that has two methods called `increment` and `decrement`.
// `increment` should increment a counter variable in closure scope and return it.
// `decrement` should decrement the counter variable and return it.
let closureCounter = 0;
const increment = () => {
return ++closureCounter;
};
const decrement = () => {
return --closureCounter;
};
return {
increment,
decrement,
};
};

const limitFunctionCallCount = (cb, n) => {
// Should return a function that invokes `cb`.
// The returned function should only allow `cb` to be invoked `n` times.
let times = 0;
return (...args) => {
if (++times <= n) {
return cb(...args);
}
return null;
};
};

/* Extra Credit */
Expand All @@ -27,6 +49,17 @@ const cacheFunction = (cb) => {
// If the returned function is invoked with arguments that it has already seen
// then it should return the cached result and not invoke `cb` again.
// `cb` should only ever be invoked once for a given set of arguments.
const cache = {};
return (...args) => {
let result;
if (!(args.toString() in cache)) {
result = cb(...args);
cache[args.toString()] = result;
} else {
result = cache[args.toString()];
}
return result;
};
};

/* eslint-enable no-unused-vars */
Expand Down
34 changes: 33 additions & 1 deletion src/objects.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
// Complete the following underscore functions.
// Reference http://underscorejs.org/ for examples.
const each = require('./arrays.js').each;

const keys = (obj) => {
// Retrieve all the names of the object's properties.
// Return the keys as strings in an array.
// Based on http://underscorejs.org/#keys
return Object.keys(obj);
};

function isFunction(func) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of consistency this should be written the same way the other functions are written.

return (typeof func === 'function');
}
const values = (obj) => {
// Return all of the values of the object's own properties.
// Ignore functions
// http://underscorejs.org/#values
const r = [];
each(keys(obj), (key) => {
if (!isFunction(obj[key])) {
r.push(obj[key]);
}
});
return r;
};

const mapObject = (obj, cb) => {
// Like map for arrays, but for objects. Transform the value of each property in turn.
// http://underscorejs.org/#mapObject
const r = {};
each(keys(obj), (key) => {
r[key] = cb(obj[key]);
});
return r;
};

const pairs = (obj) => {
// Convert an object into a list of [key, value] pairs.
// http://underscorejs.org/#pairs
const r = [];
each(keys(obj), (key) => {
r.push([key, obj[key]]);
});
return r;
};

/* Extra credit */
Expand All @@ -29,12 +50,23 @@ const invert = (obj) => {
// Returns a copy of the object where the keys have become the values and the values the keys.
// Assume that all of the object's values will be unique and string serializable.
// http://underscorejs.org/#invert
const r = {};
each(keys(obj), (key) => {
r[obj[key]] = key;
});
return r;
};

const defaults = (obj, defaultProps) => {
// Fill in undefined properties that match properties on the `defaultProps` parameter object.
// Return `obj`.
// http://underscorejs.org/#defaults
each(keys(defaultProps), (key) => {
if (obj[key] === undefined) {
obj[key] = defaultProps[key];
}
});
return obj;
};

/* eslint-enable no-unused-vars */
Expand Down