Reduce function extra bracket meaning - JS - javascript

I have a function:
function ross(array) {
return array.map(function(data) {
return data.reduce(function(obj, item) {
obj[item[0]] = item[1];
return obj;
}, {});
});
}
ross(array);
Basically this code converts the 3 dimensional array to an array of object. I want to focus on this part:
return data.reduce(function(obj, item) {
obj[item[0]] = item[1];
return obj;
}, {});
Under the return obj, you'll see another extra {} brackets beside the comma (,). Not sure what it really does if it's a callback or what. But I tried to played with it by changing it to [], and it's actually changing the output into two dimensional array.
Anyone out there who could explain what the extra bracket does?

Those {} define an empty object. The second argument to reduce is a seed value for the accumulator that's passed to your callback. So that {} is defining what your callback sees as obj on the first call (and all subsequent calls, because it returns obj).
That code is functionally identical to:
var obj = {};
data.forEach(function(item) {
obj[item[0]] = item[1];
});
return obj;
reduce is just being used (some would say abused, since the accumulator never changes; but it's really common) to make that one outermost statement rather than three.

From MDN: "The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value."
The second parameter is the initial value of the accumulator, which comes into your function as the parameter obj. If you do not specify an accumulator the default is the first element from the array that reduce is invoked on.

Related

how to group an array based on a specific function?

Here, I am new to JavaScript. I am solving questions; however, I am having a problem understanding chaining more than one method together. I have been trying to understand this solution, but it took me a lot of time, and I still don't get it.
I understand that I will input the array that I needed to change according to the specific function, which I opted. I understand all of methods functions, but I don't understand their syntax here, so can someone please explain each step to me ?
const group_By = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
In as few words as possible.
Firstly they compute a ternary expression, here they are checking if the input is a function, if it is they pass it as is, otherwise they create an anonymous function that tries to access the given property. The arrow function after the colon can seem a little confusing but it's still just a function. It takes one argument called val, and returns property which key is inside the fn variable.
typeof fn === 'function' ? fn : val => val[fn]
The next step is to create a new array with new values for each of the elements. Output of this step is just a list of values to group elements on.
For instance calling it on array ["a", "bb"] with a fn='length' would return [1,2]
arr.map(typeof fn === 'function' ? fn : val => val[fn])
Then they call the .reduce function on the output array. The purpose of the reduce function is to create a single value out of all the elements slowly iterating over it. You can tell that the last step returns accumulator value back, and that it is passed as a first argument to the function called on the next element. The empty object at the end is just an initial value of the accumulator.
.reduce((acc, val, i) => {
...
return acc;
}, {});
And finally for the step that does the accumulation. Here firstly the val from the result of the map, is used to access property of the newly created object. If the value does not exist it replaced with an empty array || []. That has the element of the initial array at the same index concatenated onto it. If there were some elements it just adds new ones to it and reassigns the value.
acc[val] = (acc[val] || []).concat(arr[i]);
Okay, what I understood from your query is that you are trying to chain multiple functions together.
function Chained() {
// this reference.
const _this_ = this
this.Function1 = () => // do something and return _this_
this.Function2 = () => // do something here and return _this_
}
Above you can see that chain is a simple object which returns "this" as context. and on context, we already have Function1 and Function2. so due to this following will be valid.
const _ExecuteChained = new Chained()
// Now you can run _ExecuteChained.Function1().Function2() and so on.
Now coming to your code.
const group_By = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val,
i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
Here you are just running a loop on arr and validating if the second param is a function or not if function then return it as is (Since you are using a map it will be stored at the given index. else just get the value of the function at the given key and return it.
Reduce.
in Reduce you are trying to accumulate a given value with (contact or merge or extend) value at a given index of arr in this case function.

Is there a way to change the original reference to an object in a function call

I was working with an array in JavaScript and was wondering why changes I made to an array were correctly saving to localStorage, but weren't being reflected in the array past the function call. The code was the following:
function removeFromList(array, arrayName, key) {
array = array.filter(function(element) { return element.key !== key; });
localStorage.setItem(arrayName, JSON.stringify(array));
}
I did some googling and, through some old posts, discovered that the array was being passed by value to the function, that is, the array variable, which pointed to an array object, was being passed by value, and changing that copy did not affect the original variable that was pointing to my array object.
I came up with the following code as a workaround:
function removeFromList(array, arrayName, key) {
arrayTemp = array.filter(function(element) { return element.key !== key; });
for(var i = 0; i < array.length; i++) {
if (!arrayTemp.some(item => item.key === array[i].key)) {
array.splice(i, 1);
}
}
localStorage.setItem(arrayName, JSON.stringify(array));
}
This solved my problem, and the new contents of the array was displayed in both localStorage and the array object that was pointed to by the original variable. However, I've been wondering if there is some new way introduced into JavaScript recently or an older method I did not find that would do a better job of achieving the desired result.
I did some googling and, through some old posts, discovered that the array was being passed by value to the function, that is, the array variable, which pointed to an array object, was being passed by value, and changing that copy did not affect the original variable that was pointing to my array object.
Exactly right.
Is there a way to change the original reference to an object in a function call
No, JavaScript is still a purely pass-by-value language. While I suppose it's possible for that to change at some point, it hasn't as of this writing (and it seems really unlikely to me it ever will). If you do example(x) when x contains 42 (or an array reference), there still isn't any way for example to reach out and change the value of x (to 43, or to refer to a different array). If x refers to a mutable object (like an array), example can modify that object, but it can't make x refer to a whole new object.
Your workaround works by modifying the existing array. FWIW, in general it would be preferred to return the new array instead, so the caller has the option of either keeping the original or using the new one. E.g.:
function removeFromList(array, arrayName, key) {
array = array.filter(function(element) { return element.key !== key; });
localStorage.setItem(arrayName, JSON.stringify(array));
return array;
}
And then when using it:
variableContainingArray = removeFromList(variableContainingArray, "nameInLocalStorage", 42);
But if you want to update in place, you don't need a temporary array:
function removeFromList(array, arrayName, key) {
// Looping backward we don't have to worry about the indexes when we remove an entry
for (let i = array.length - 1; i >= 0; --i) {
if (array[i].key === key) {
array.splice(i, 1);
}
}
localStorage.setItem(arrayName, JSON.stringify(array));
}
Instead of using a for-loop to remove the values from the argument array you can also empty it out using splice and add the filtered values:
function removeFromList(array, arrayName, key) {
var filtered = array.filter(function(element) { return element.key !== key; });
array.splice(0, array.length, ...filtered);
localStorage.setItem(arrayName, JSON.stringify(array));
}
I suggest changing var to const and function(element) { return element.key !== key; } to element => element.key !== key if those features are available within your runtime environment.

findKey() - recreating lodash library method

I've got a problem with a CodeCademy task. I am to re-create the findKey lodash library method. Here there are the steps of how to do it, but I got stuck, especially at point 5.
Add a method to our _ object called findKey.
Add two parameters to this method: object and predicate. We will
name our predicate function parameter predicate since this is the
name used in the Lodash documentation.
Within the method, use a for ... in loop to iterate through each key
in object.
Within the loop, create a variable called value and set it equal to
the value at the current key in object.
Still within the loop, create another variable called
predicateReturnValue and set it equal to the result of calling
predicate with value.
Finally, still within the loop, use an if statement to check
if predicateReturnValue is truthy. If it is, return the current key
from the method.
Outside of the loop, return undefined to address all cases where no
truthy values were returned from predicate.
This is my code that doesn't work:
findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue === 'true') {
return value;
};
};
return undefined;
}
I appreciate your help!
You need to return the key after the truty check of the call of predicate.
function findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) { // just take the value
return key; // return key
}
}
}
const
isStrictEqual = a => b => a === b,
object = { a: 'foo', b: 'bar', c: 'baz' }
console.log(findKey(object, isStrictEqual('bar')));
console.log(findKey(object, isStrictEqual('cat')));

How do I assign my .reduce function output to a variable?

Given an object and a key, getElementsThatEqual10AtProperty returns an array containing all the elements of the array located at the given key that are equal to ten.
I want to assign what my .reduce method outputs to a variable then use that variable inside my if statement. My code evaluates to NaN.
function getElementsThatEqual10AtProperty(obj, key) {
var arrayTotal = 0;
obj[key].reduce(function(a,b){
arrayTotal = a + b;
});
if(arrayTotal === 10) {
return obj[key];
}
};
You're approaching reduce incorrectly. You're almost using it like Array#forEach. Remember that callbacks are functions. They expect to return an actual value.
When you read the docs, you'll see that reduce also needs an accumulator, that is an argument after the callback.
const sum = obj[key].reduce(function(a,b){
return a + b
}, 0)
Or if you want the newer and prettier version:
const sum = obj[key].reduce((a,b) => a + b, 0)
When you have a one liner, return is implicit, which means it's implied, as opposed to explicit.
The accumulator is what your value starts at while it totals up the values.
Array.reduce(callback, accumulator)

Array to Object First and Last

I need to take the first and last element in a given array and return an object with the first element as the key and the last as the value.
Here's my code:
function transformFirstAndLast(array) {
array=[];
var object={};
object[key]=value;// make object
var key=array[0];
var value=array[array.length-1];
return object;} // return object
for whatever reason, it's returning undefined inside the object. I swear it was working this morning...
I've always tried:
function transformFirstAndLast(array) {
array=[];
var object = {};
object[array[0]] = array[array.length-1];}
but that's returning undefined without so much as an object being built.
This is straightforward using computed property names:
function transformFirstAndLast(array) {
return {[array[0]]: array[array.length - 1]};
}
Or if you prefer:
const transformFirstAndLast = ([head, ...tail]) => ({[head]: tail.pop()});
You're redeclaring array at the beggining of your function.
Besides, in my opinion, using "array" and "object" as variable names is a bad idea. Just a typo could get you messing up with Array and Object. And that might have side effects.
Here's a functional fiddle for your use case using array.shift() and array.pop() methods.
var myArray=['one','two','three','four'];
function buildObject(arr) {
var myObject={},
key=arr.shift(),
val=arr.pop();
myObject[key]=val;
return myObject;
}
console.log(buildObject(myArray));

Categories