What I have here is an algorithm that finds the highest value in each subarray and pushes it onto a separate array (final).
I want to let the variable 'value' equal to the lowest possible number so that any negative number can be considered higher than 'value'
function largestOfFour(arr) {
var final=[];
arr.map(sub => {
let value = 0; //issue
sub.map(num => {
if(num>value){value=num};
})
final.push(value)
})
return final;
}
console.log(largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]));
In this example the last subarray returns 0 since non of the numbers in that subarray were higher than the initial value of 'value' which is 0.
I want it to return '-3' instead since it's the highest number in the subarray.
It would appear you're simply looking for the max of each array.
Using Array#map and Math#max and spread syntax you could do something like this.
const data = [[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]];
const res = data.map(arr=>Math.max(...arr));
console.log(res);
You can just set value to Number.NEGATIVE_INFINITY but for what it's worth, I'd recommend simply using reduce instead of map in your inner function. That way, the inner loop will start with sub[0] as an initial value rather than depending on any placeholder.
function largestOfFour(arr) {
var final = arr.map(sub => sub.reduce((num, value) => Math.max(num, value)));
return final;
}
console.log(largestOfFour([
[17, 23, 25, 12],
[25, 7, 34, 48],
[4, -10, 18, 21],
[-72, -3, -17, -10]
]));
Related
If I use [3, 8, -10, 23, 19, -4, -14, 27].sort((a,b)=>a-b) it works.
But if I use...
leaderboard = (fs.readFileSync('leaderboard.txt', 'utf-8'))
[leaderboard].sort((a,b)=>a-b)
...it just sends the numbers unsorted.
leaderboard.txt = 3, 8, -10, 23, 19, -4, -14, 27
The leaderboard is just a string when it's read from a file.
Assuming that the file contains '3, 8, -10, ...', you should first split the string to an array. then cast item(with type string) to number and then sort.
const sortedLeaderBoard = leaderboard
.split(', ')
.map(Number)
.sort((a, b) => a - b);
console.log(sortedLeaderBoard);
is my assumption correct?
["Ahmed", 8],
["Clement", 10],
["Elamin", 6],
["Adam", 7],
["Tayoa", 11],
["Nina", 10],
["Bob", 9],
["Lee", 1]
In the above array, how can I retrieve names value whose second key value is greater than 8?
any help appriciated.Thank you
This approach requires iterating over the array twice by first filtering out the invalid elements and then mapping over the array to pluck out the name.
Note that this is leveraging array destructuring which allows us to nicely give the value at a given index a name, rather than trying to remember the index offset and what it means.
const data = [
["Ahmed", 8],
["Clement", 10],
["Elamin", 6],
["Adam", 7],
["Tayoa", 11],
["Nina", 10],
["Bob", 9],
["Lee", 1]
]
const filtered = data.filter(([_name, num]) => num > 8).map(([name]) => name)
console.log(filtered)
You can reduce() the array in one pass by checking if the second element in the array (age?) is more than 8, if so, add the first element in the array (the name) to the accumulator array, like so:
let arr = [
["Ahmed", 8],
["Clement", 10],
["Elamin", 6],
["Adam", 7],
["Tayoa", 11],
["Nina", 10],
["Bob", 9],
["Lee", 1],
];
let result = arr.reduce((acc, [name, age]) => (age > 8 && acc.push(name), acc), []);
console.log(result);
When chaining the Array.prototype.reduce with Array.prototype.filter what is the difference (conceptually and under the hood) when filtering on the current value instead of the accumulator value?
// function union creates a union of all values that appear among arrays
// example A
const union = (...arrays) => {
return arrays.reduce((acc, curr) => {
const newElements = acc.filter(el => !curr.includes(el));
return curr.concat(newElements);
});
};
console.log(union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]));
// output (7) [1, 10, 15, 5, 88, 7, 20]
// example B
const union = (...arrays) => {
return arrays.reduce((acc, curr) => {
const newElements = curr.filter(el => !acc.includes(el));
return acc.concat(newElements);
});
};
console.log(union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]));
//output (7) [1, 10, 15, 20, 5, 88, 7]
The difference in output would suggest that the order in which the arrays are being evaluated is 'opposite'. As far as I can tell when using arr.filter the values are evaluated from end to beginning with the opposite being true for curr.filter . Besides from that are they any other consequences dependent on if you filter through the accumulator or current value? Could this throw an error in a different context?
The issue isn't about the use of filter inside of reduce, so much as it is about the order in which you're using acc and curr.
When I'm running into seemingly strange inconsistencies like this, the first step I usually take is to create a test case and run through it manually. Here, you've already created a test case for us...
const testData = [
[1, 10, 15, 20],
[5, 88, 1, 7],
[1, 10, 15, 5],
]
Now we need to run through each version of the function and see what the output is at each stage.
One thing to note (which I didn't know until this evening!) is that if reduce doesn't receive an initialValue as the second argument, it will use the first item in the array as the initialValue. This means we only need to consider 2 executions of each function instead of 3. 😅
Example A
const union = (...arrays) => {
return arrays.reduce((acc, curr) => {
const newElements = acc.filter(el => !curr.includes(el))
return curr.concat(newElements)
})
}
In the first version of the function, the short description of what's happening is that we're looping over the accumulator (acc) and removing all items that already exist in the array that we're currently comparing (curr). Then we add that list to the end of curr.
The fact that we’re pushing newElements onto the end of curr is important. This is why the order is different for the 2 different versions.
First execution
const acc = [1, 10, 15, 20]
const curr = [5, 88, 1, 7]
const newElements = [10, 15, 20] // these elements exist in acc but not in curr
curr.concat(newElements) === [5, 88, 1, 7, 10, 15, 20]
Second execution
const acc = [5, 88, 1, 7, 10, 15, 20] // carried over from first execution
const curr = [1, 10, 15, 5]
const newElements = [88, 7, 20] // these elements exist in acc but not in curr
curr.concat(newElements) === [1, 10, 15, 5, 88, 7, 20]
Example B
const union = (...arrays) => {
return arrays.reduce((acc, curr) => {
const newElements = curr.filter(el => !acc.includes(el))
return acc.concat(newElements)
})
}
In the first version of the function, the short description of what's happening is that we're looping over the array that we’re currently comparing (curr) and removing all items that already exist in the accumulator (acc). Then we add that list to the end of acc.
You can already see at the end of the first execution below that the results are turning out in a much different order.
First execution
const acc = [1, 10, 15, 20]
const curr = [5, 88, 1, 7]
const newElements = [5, 88, 7] // these elements exist in curr but not in acc
acc.concat(newElements) === [1, 10, 15, 20, 5, 88, 7]
Second execution
const acc = [1, 10, 15, 20, 5, 88, 7] // carried over from first execution
const curr = [1, 10, 15, 5]
const newElements = [] // these elements exist in acc but not in curr
acc.concat(newElements) === [1, 10, 15, 20, 5, 88, 7]
Conclusion
The short answer to your question is that the difference between filtering on the accumulator and the current array is that the results are going to be different so long as the inputs are different. 🤷🏻♂️
Besides from that are they any other consequences dependent on if you filter through the accumulator or current value? Could this throw an error in a different context?
Fortunately, there’s not any concern about errors. It is notable, however, that the second version of your function is ~10% faster than the first version. I’d guess that this is purely circumstantial. A different test data set may produce different performance results.
In example 1, by the time you concat the two lists, you make sure that the accumulator won't contain any element from current.
In example 2, on the other hand, you make sure that current won't contain any element that is already present in accumulator.
The difference is on the final order in which the elements will appear
I think both examples are not efficient since they both involve O(n2) time complexity, since you are nesting iterations. The second one, as stated by others, might be a little more performant since the nested iterations would be made on a chunk that is presumably shorter than the accumulator.
I'd rather write more or less like this:
const union = (...tuples) => Array.from(
new Set(
tuples.flatMap(n => n),
)
);
console.log(
union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]),
);
I am trying to figure out why my call to .prototype.filter is giving me a TypeError: curr.filter is not a function.
const intersection = (arrays) => {
return arrays.reduce((acc, curr) => {
return curr.filter(el => acc.includes(el));
});
};
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
To my understanding I am declaring a function const intersection which takes in arrays and then returns the result of calling arrays.reduce which 'reduces' the results of filtering the current value and creating a new array that includes all instances of accumulator acc including the current value curr.
Since filter creates a new array on runtime I figured this would work as is yet it does not. What am I not seeing?
Use array rest parameter to get all parameter as an array. In the given code you are taking just first argument and ignoring the rest.
try this.
const intersection = (...arrays) => {
console.log("arrays: ", arrays);
return arrays.reduce((acc, curr) => {
return curr.filter(el => acc.includes(el));
});
};
console.log("Result:" , intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
I have this array of Object that I am getting from my database:
[Array of Object][1]
I would like to make an array of array for each value, but I can't manage to find a way to do it as I'm a beginner of javascript.
For example :
var Stats=[
[39,49,43,42,41,35], //SGW Value for each Object
[37,44,49,46,52,42], //UD Value for each Object
[8,11,8,8,16,15], //Virtual Value for each Object
...
]
The goal is to make a chart on chart.js that look like that :
[Chart Goal][2]
I would need to loop the dataset because I'll add more data and it would be way too long to set each dataset individually.
Thanks for your time.
You can do it like this:
let array1 = [
{
param1: 10,
param2: 20
},
{
param1: 30,
param2: 40
}
]
let array2 = array1.map(item => Object.values(item));
console.log(array2); // prints [[10, 20], [30, 40]]
First of all you need to create an array for each property you want to plot; i.e.:
var fsp = [],
msg = [],
sgw = [];
Then you can loop over your dataset and put the data in each array:
yourArray.forEach(function(obj){
//obj takes the value of each object in the database
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
})
or, if you are more familiar with for loop
for(var obj of yourArray){
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
}
Finally you can create an array as you pointed in your example
var result = [];
result.push(fsp, msg, sgw);
And the result will be
[
[89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
[77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
[24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
]
For more informations take a look at Array.forEach(), Array.push() and for...of documentations
EDIT
As you pointed in your comment, you can generate arrays dynamically creating an object like var arrays = {};. Then in forEach(), or if for...of, you need to loop over objects with a for...in loop. The variable you declare in loop's head takes the value of index, numeric for Arrays, literal for Objects. You have to do something like:
yourArray.forEach(function(obj){
for(let index in obj){
if(!arrays[index]) // check if property has already been set and initialized
arrays[index] = []; // if not, it's initialized
arrays[index].push(obj[index]) // push the value into the array
}
})
Note that Object has been treated as Array because you access its properties with a variable filled at runtime.
The result will be:
arrays = {
fsp: [89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
msg: [77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
sgw: [24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
}
To obtain only arrays use Object.values().
If you cannot imagine how this works, I suggest you to make some examples in Chrome Developer Tools' console, or in Node's console, or wherever you can have a realtime feedback, putting in the middle of code some console.log() of variables