Find max In array where items may be numbers or arrays - javascript

I want to find the maximum value in an array where each value may be either a positive number or another array of positive numbers. I have this, but I'm not sure how to deal with the nested arrays.
var array = [5, 8, 15, [10, 2, [6, 20, 1], 4, 13, [2, 11]]];
function findMax(arr) {
var max = 0;
for (var i = 0; i < arr.length; i++) {
// what if it's an array?
if (arr[i] > max) {
max= arr[i];
}
}
return max;
}
console.log(findLargest(array));
// answer should be 20

function findMax(arr) {
return arr.reduce((prev, curr) => Math.max(prev, Array.isArray(curr) ? findMax(curr) : curr), 0);
}
console.log(findMax(array));

Just flatten it first?
var array = [5, 8, 15, [10, 2, [6, 20, 1], 4, 13, [2, 11]]];
const findMax = arr => Math.max(...array.flat(Infinity));
console.log(findMax(array));

Related

how to Find the maximum number in a jagged array given below array of numbers?

how to Find the maximum number in a jagged array given below array of numbers?
const array= [2,4,10,[12,4,[100,99],4],[3,2,99],0];
If you know the maximum depth of nesting, then you can flat the array and find the maximum:
Math.max(...array.flat(depth));
If you don't know the maximum depth, you need to iterate over all the items recursively:
const findMax = item => Math.max(...item.map(row => Array.isArray(row) ? findMax(row) : row));
console.log(findMax([2,4,10,[12,4,[100,99],4],[3,2,99],0]));
You can flat the jagged array using flat method and after that find max in it. like:
const array = [2,4,10,[12,4,[100,99],4],[3,2,99],0];
const flatArray = array.flat(2);
console.log("Max Value is "+ Math.max(...flatArray));
if you don't know the level of depth
let array = [2, 4, 10, [12, 4, [100, 99], 4], [3, 2, 99], 0 ]
let max = 0
function maxNumber(array) {
for (let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
maxNumber(array[i])
} else {
if (array[i] > max) {
max = array[i]
}
}
}
}
maxNumber(array)
console.log(max)
You could reduce the array and check if the value is an array, then reduce this array or take the value for the wanted function.
const
reduceBy = fn => {
const r = array => array.reduce((a, b) => fn(
Array.isArray(a) ? r(a) : a,
Array.isArray(b) ? r(b) : b
));
return r;
},
array = [2, 4, 10, [12, 4, [100, 99], 4], [3, 2, 99], 0],
result = reduceBy(Math.max)(array);
console.log(result);
var arr = [2, 4, 10, [12, 4, [100, 99], 4], [(3, 2, 99)], 0];
function getMax(a) {
return Math.max(...a.map((e) => (Array.isArray(e) ? getMax(e) : e)));
}
console.log(getMax(arr));

removing duplicate ids from array of arrays from a specific index

I want to remove duplicate ids from pureIDs[2]. so the index here is 2. the only condition is the arrays I want to search for duplicates are the ones with lower indices so I want to search 0 and 1.
If we want to pureIDs[3] then we should search 0 , 1 , 2 (the lower indices)
My attempt is a total failure Here:
The desired result is : [22, 9] here.
const pureIDs = [
[0, 1, 23, 5, 11],
[2, 15, 23, 25, 10],
[2, 10, 22, 9, 11], // Modify this index (2)
[20, 24],
];
// I give the index here
const ids = getModifiedIDs(pureIDs[2], 2);
console.log(ids); // This should result in : [22, 9]
function getModifiedIDs(ids, from) {
let sets = [];
for(let b = from - 1; b > -1; b--){
console.log(b)
set = ids.filter((el) => {
return !pureIDs[b].includes(el);
});
sets.push(set)
}
return sets;
}
Just a slight modification gives you the result needed.
Change your function to:
function getModifiedIDs(ids, from) {
const set = ids.filter((el) => {
for(let b = from - 1; b > -1; b--){
if (pureIDs[b].includes(el)) {
return false;
}
}
return true;
});
return set;
}
Build a set from the arrays with deletable indexes. Than you get with Array#filter and Set#has your result.
function getModifiedIDs(ids, from) {
let dels = [];
for (i=0; i<from-1; i++)
dels = dels.concat(pureIDs[i]);
let delSet = new Set(dels);
return ids.filter(id => !delSet.has(id) );
}
const pureIDs = [
[0, 1, 23, 5, 11],
[2, 15, 23, 25, 10],
[2, 10, 22, 9, 11], // Modify this index (2)
[20, 24],
];
console.log(getModifiedIDs(pureIDs[2], 3));

Union between three arrays

I need to find the union of three arrays that get passed to the function union.
It took me about 50lines to code to get the expected result. Apparently, the following code works but now I wonder what are the best ways (either in a functional and in a non-functional fashion) to do the same job.
function union(...arrays) {
var array1 = arguments[0];
var array2 = arguments[1];
var array3 = arguments[2];
var unique = [];
var intersaction = [];
// find the unique values
for(let i = 0; i < array1.length; i++) {
if( (array2.includes(array1[i]) == false) && (array3.includes(array1[i])) == false ) {
unique.push(array1[i]);
}
}
for(let i = 0; i < array2.length; i++) {
if( (array1.includes(array2[i]) == false) && (array3.includes(array2[i])) == false ) {
unique.push(array2[i]);
}
}
for(let i = 0; i < array3.length; i++) {
if( (array1.includes(array3[i]) == false) && (array2.includes(array3[i])) == false ) {
unique.push(array3[i]);
}
}
// find the intersection
for(let j = 0; j < array1.length; j++) {
if(array2.includes(array1[j]) || array3.includes(array1[j]) ) {
if (intersaction.indexOf(array1[j]) == -1) {
intersaction.push(array1[j]);
}
}
}
for(let j = 0; j < array2.length; j++) {
if(array1.includes(array2[j]) || array3.includes(array2[j]) ) {
if (intersaction.indexOf(array2[j]) == -1) {
intersaction.push(array2[j]);
}
}
}
for(let j = 0; j < array3.length; j++) {
if(array1.includes(array3[j]) || array2.includes(array3[j]) ) {
if (intersaction.indexOf(array3[j]) == -1) {
intersaction.push(array3[j]);
}
}
}
return union = [...intersaction, ...unique];
}
console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]));
// should log: [5, 10, 15, 88, 1, 7, 100]
Just another solution keeping the original function signature provided by the OP:
function union(...arrays) {
return Array.from(new Set([...arrays].flat()));
}
console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]));
Or, even shorter (but less read friendly):
return [...(new Set([...arrays].flat()))];
Explanation:
Array.from takes an Iterable as an argument, this will create a new array from the original one.
[...arrays] spreads the arrays (argument) into a new, single, one (So it becomes an array of arrays) -> [5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5] becomes: [[5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]]
.flat flattens the array, making that an array of values rather than ar array of arrays of values -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat -> [[5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]] becomes [5, 10, 15, 15, 88, 1, 5, 7, 100, 15, 10, 1, 5]
new Set removes duplicates from the array and returns an Iterable https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set. -> [5, 10, 15, 15, 88, 1, 5, 7, 100, 15, 10, 1, 5] becomes a Set instance (an Iterable) without the duplicates. Array.from then converts the Set (Iterable) to a regular array. Further infos here: How to convert Set to Array?
BEWARE: Array.flat is currently an experimental feature (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat). Solution without using flat below:
function union(...arrays) {
return Array.from(new Set([].concat.apply([],[...arrays])));
}
console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]));
Explanation (only differences from above):
Instead of .flat, we apply to Array.concat our original array, so that it will flatten it passing a new array as its this and providing our array as the argument: [].concat.apply([],[...arrays])
Snippet: http://jsfiddle.net/briosheje/y03osape/2/
Snippet without .flat: http://jsfiddle.net/briosheje/y03osape/4/
use set that's very simple,
The Set object lets you store unique values of any type, whether
primitive values or object
var a= [5, 10, 15];
var b=[15, 88, 1, 5, 7];
var c=[100, 15, 10, 1, 5];
var result= [...new Set([...a, ...b,...c])];
console.log(result);
I tried to copy your approach of looping over arrays but in a slightly more efficient manner, using only ES5 safe functions. I'm sure the other answers are more efficient if you can use the features they do.
var a = [1, 2, 3];
var b = [1, 2, 4, 5];
var c = [2, 7, 9];
// takes an array of arrays
function getUnique(input) {
var unique = [];
// loop over each array
input.forEach(function(item) {
// loop over each value
item.forEach(function(value) {
// if it's not already in the unique array,
if (unique.indexOf(value) == -1) {
// add it
unique.push(value);
}
});
});
return unique;
}
// takes an array of arrays
function getIntersection(input) {
// assume all elements in first array are common
var intersection = input.shift();
var remove = [];
// loop over items in first array and attempt to
// disprove commonality
intersection.forEach(function(value) {
// loop over subsequent arrays
for (var i = 0; i < input.length; i++) {
var item = input[i];
// if these arrays don't contain the value,
// then it isn't an intersection
if (item.indexOf(value) == -1) {
// add it to an array to be removed
remove.push(value);
// exit this loop
break;
}
}
});
// remove values determined not to be intersections
remove.forEach(function(value) {
intersection.splice(intersection.indexOf(value), 1);
})
return intersection;
}
var test = getUnique([a, b, c]);
console.log(test);
var test2 = getIntersection([a, b, c]);
console.log(test2);
Based on custom forEach and Reduce from previously in the exercise at http://csbin.io/callbacks
function forEach(array, callback) {
for(i = 0; i < array.length; i++){
callback(array[i])
}
}
function reduce(array, callback, initialValue) {
for(let i of array){
initialValue = callback(initialValue, i)
}
return initialValue
}
function union(...arrays) {
return reduce(arrays, (seen, next) => {
forEach(next, (element) => {
if(!seen.includes(element)) seen.push(element);
})
return seen
}, [])
}
Note if you use the in-built reduce function you can remove the empty inital array requirement.

Codewars javascript task - help to understand

I am taking an excercise on codewars:
Given a list of integers and a single sum value, return the first two
values (parse from the left please) in order of appearance that add up
to form the sum.
Example:
sum_pairs([10, 5, 2, 3, 7, 5], 10)
# ^-----------^ 5 + 5 = 10, indices: 1, 5
# ^--^ 3 + 7 = 10, indices: 3, 4 *
# * entire pair is earlier, and therefore is the correct answer
== [3, 7]
What do you think entire pair is earlier means? IMO if the sum of it's indexes is smallest. Now based on this assumption I made my solution and one test fails:
var sum_pairs=function(ints, s){
let i = 0;
let pair = [0, 0];
let ind = [100, 100]
let found = false;
function loop(i) {
if (i > ints.length) return pair;
ints.slice(i).forEach((curr, idx) => {
ints.slice(i+1).some((num, i) => {
let sum = curr + num;
let prevIndicies = ind[0] + ind[1];
if(sum === s && prevIndicies > idx + i) {
ind = [idx, i];
pair = [curr, num];
found = true;
return true;
}
})
})
i += 1;
loop(i)
}
loop(0)
if (found) {
return pair
}
return undefined;
}
console.log(sum_pairs([1,4,8,7,3,15], 8))
Test returns error that [1, 7] is expected.
I'm pretty sure what it means is they want the second element to be as leftward in the list as possible. For example, for
l5= [10, 5, 2, 3, 7, 5];
when trying to find a sum of 10, the desired output is
[3, 7]
[10, 5, 2, 3, 7, 5];
^ ^
instead of
[5, 5]
[10, 5, 2, 3, 7, 5];
^ ^
because the last element in [3, 7], the 7, came before the second 5.
This code seems to pass all test cases - iterate in a triangular fashion, starting at indicies [0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3], ...:
const sum_pairs = function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
const sum_pairs=function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
l1= [1, 4, 8, 7, 3, 15];
l2= [1, -2, 3, 0, -6, 1];
l3= [20, -13, 40];
l4= [1, 2, 3, 4, 1, 0];
l5= [10, 5, 2, 3, 7, 5];
l6= [4, -2, 3, 3, 4];
l7= [0, 2, 0];
l8= [5, 9, 13, -3];
console.log(sum_pairs(l1, 8))
console.log(sum_pairs(l2, -6))
console.log(sum_pairs(l3, -7))
console.log(sum_pairs(l4, 2))
console.log(sum_pairs(l5, 10))
console.log(sum_pairs(l6, 8))
console.log(sum_pairs(l7, 0))
console.log(sum_pairs(l8, 10))
It means that you go from left to right and take the first matching pair, and since 7 is the first element that creats a pair (going from the left) 3 and 7 is the first pair.
I would solve it a bit easier:
function sum_pairs(arr, target) {
let old = [];
let result = [];
arr.some((el) => {
let found = old.find((oldEl) => oldEl + el === target);
if (found) return result = [found, el];
old.push(el);
})
return result;
}
sum_pairs([10, 5, 2, 3, 7, 5], 10);
Edit: an explaination. I loop over all elements in the array searching for a match i all the elements I have passed. If I find a match I remember it and break out of the loop by returning a "truthy" value. (That is just how .some() works.) Finally if I have not found a match I add the element to my list of old elements and go on to the next.
function sum_pair(arr,sum){
let result = [];
arr.forEach((i, j)=>{
if(i+arr[j+1]===sum){
console.log(i,arr[j+1], i+arr[j+1])
}
})
}
sum_pair([0, 3, 7, 0, 5, 5],10)

Comparing Multiple Arrays Using Reduce

pretty new to Javascript and I've tried this question about 4 times now in a span of about a month and I am still unable to solve it.
So here is the question:
Construct a function intersection that compares input arrays and returns a new array with elements found in all of the inputs. BONUS: Use reduce!
The format is:
function intersection(arrays) {
// Your Code Goes Here
}
Test Case: Should log [15, 5]
console.log('Extensions 3 Test: ' + intersection([5, 10, 15, 20], [15, 88, 1, 5, 7]/*, [1, 10, 15, 5, 20]*/));
My current solution: Works for the case of only have two items to compare, but not for the third one, I could make it so that I would loop through and compare the obtained values with the next array but I don't think I am on the right path... Also, I am not using reduce to implement it... And I am not sure if I am supposed to be using 'arguments.' Any help is appreciated! Thank you so much.
function intersection(arrays) {
array = [];
for (var i = 0; i < arguments.length; i++)
array.push(arguments[i]);
var result = [];
for(var i = 0; i < array.length - 1; i++) {
for(var j = 0; j < array[i].length; j++) {
if (array[i+1].includes(array[i][j]))
result.push(array[i][j]);
}
}
return result;
}
Although, as several suggestions said, you could use underscore, lodash, or my personal favorite, Ramda (disclaimer: I'm one of the authors), this function should be straightforward enough that you wouldn't even consider a library for it. Here's a simple version:
const intersection = (xs, ys) => xs.filter(x => ys.indexOf(x) > -1);
intersection([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7]); //=> [5, 15, 3]
const intersectAll = (...xss) => xss.reduce(intersection);
intersectAll([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7], [1, 10, 15, 5, 20]); //=> [5, 15]
I would think that this is all you need, at least so long as you're worried only about reference/primitive equality and don't need to consider cases where you want to know that {x: 1} and {x: 1} are the same, even though they aren't the same reference. If you do need that, you might look to Ramda's intersection function.
Note that if includes were better supported, I would recommend this version instead, as it reads better:
const intersection = (xs, ys) => xs.filter(x => ys.includes(x));
Also, if you have no need for the binary function, you can make just a variadic version of it by combining the two above:
const intersection = (...xss) => xss.reduce((xs, ys) => xs.filter(x => ys.indexOf(x) > -1));
Maybe someone will finds it useful.
As an argument to the function you can give any number of arrays of any length and the function is compact, I think ;)
const findSimilar = (...arrays) => {
return arrays.reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
};
console.log(
findSimilar([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20])
);
And how it works:
Ok, first u take rest parameters(...arrays) as parameter of function, so u have
arrays = [ [5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20] ]
then in first iteration of reduce we have
includ = [5, 10, 15, 20] and current = [15, 88, 1, 5, 7]
on this two we use filter, what give us [5,15], i use Set to make shure there is no repetition and make array back (Array.from()), which is passed to the next iteration of reduce as "includ", at the next iteration we have
incude = [5,15] and current = [1, 10, 15, 5, 20] and so on ...
We can even use it like this
let result = [
[5, 10, 15, 20],
[15, 88, 1, 5, 7],
[1, 10, 15, 5, 20]
].reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
console.log(result);
Although not solving your problem directly, you can do what you're trying to do using the opensource library underscore.js.
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
You may be able to derive inspiration from the way that's been implemented. The above is the function call to their own _.intersection function which is also dependent on other underscore.js functions as you see below:
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
Here is a solution using reduce, with the empty array passed in as intersection as the initial value.
Iterate the numbers and check if each one appears in one of the subarrays.
If it doesn't, set the Boolean isPresentInAll to false.
If it does appear in all three and it's not already present in the
intersection array, then push to the intersection array.
function intersection(arrayOfArrays) {
return arrayOfArrays.reduce(function(intersection, subArray) {
subArray.forEach(function(number) {
var isPresentInAll = true;
for (var i = 0; i < arrayOfArrays.length; i++) {
if (arrayOfArrays[i].indexOf(number) === -1) {
isPresentInAll = false;
}
}
if (isPresentInAll === true && intersection.indexOf(number) === -1) {
intersection.push(number);
}
});
return intersection;
}, []);
}
I think i got the right function for you.
(Note: results are not sorted!)
var intersection = function() {
// merge deduped arrays from arguments
var arrays = Array.prototype.reduce.call(arguments, function(carry, array) {
return [].concat(carry, array.filter(function(item, index, origin) {
return origin.indexOf(item) === index;
}));
}, []);
var results = arrays.reduce(function(carry, item, index, arr) {
if(
// just select items, which have more then 1 occurance
arr.filter(function(fItem) {
return fItem === item;
}).length > 1 &&
// ... and which are not already in results
!~carry.indexOf(item)
) {
carry = [].concat(carry,item);
}
return carry;
}, []);
return results;
};
Here's a version that uses 2 reduces.
The first iterates the arrays only once to create a hashmap object to track instance counts, the second to return values where counts match number of arguments
function intersection(){
// convert arguments to array of arrays
var arrays = [].slice.call(arguments);
// create an object that tracks counts of instances and is type specific
// so numbers and strings would not be counted as same
var counts= arrays.reduce(function(a,c){
// iterate sub array and count element instances
c.forEach(function(val){
var propName = typeof val + '|' + val;
// if array value not previously encountered add a new property
a[propName] = a[propName] || {count:0, value: val};
// increment count for that property
a[propName].count++;
});
return a;
},{});
// iterate above object to return array of values where count matches total arrays length
return Object.keys(counts).reduce(function(resArr, propName){
if(counts[propName].count === arrays.length){
resArr.push(counts[propName].value);
}
return resArr;
},[]);
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]))
Could use some fine tuning to make sure there are enough arguments and that they are all arrays
Here's what I came up with using vanilla javascript and one call to reduce.
function intersection(){
var arrays = [].slice.call(arguments);
var first = arrays[0];
var rest = arrays.slice(1);
return first.reduce(function(all, item, index){
var push = rest.every(function(subArray){
return subArray.indexOf(item) > -1;
});
if(push){
all.push(item);
}
return all;
},[])
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
function intersection(arrays) {
let common = arrays.reduce(function(accumulator, currentValue) {
return accumulator.filter(function(x){
return currentValue.indexOf(x) > -1;
})
})
return common;
}
To optimize your answer that couldn't work on more than 2 subarrays and didn't use reduce, here's the code that works for however many subarrays you pass in.
function intersection(arr1, arr2, arr3){
let ans = arr1[0]; // ans = [5,10,15,20]
for(let i = 0; i < ans.length; i++){ // i = 0...3
for(let j = 1; j < arr1.length; j++){ // j = 1...2
if(!(arr1[j].includes(ans[i]))){ // if the new subarray doesn't include an element in the ans
ans.splice(i, 1); // delete the element from ans
}
}
}
return ans;
}
const arr1 = [5, 10, 15, 20];
const arr2 = [15, 88, 1, 5, 7];
const arr3 = [1, 10, 15, 5, 20];
console.log(intersection([arr1, arr2, arr3])); // should log: [5, 15]

Categories