javascript - get row with max value in multi dimesion array - javascript

I have an array like
var arr = [ [1, 4, 5],
[2, 6, 7],
[3, 3, 9]]
I would like to get the row which has max value in column 2, so in this example row 2. How can I do this in javascript?
Edit: I can do it using a for loop which iterates over all rows and have a temp max variable to keep track of the max. But I was hoping for a more efficient way.
Thanks

Well, iterating and keeping a temporary max variable is probably the most efficient way of doing it, but if you want a way that looks more pleasing, you can try something like:
var col2 = arr.map(function (elem) {
return elem[1]; //to get all the column 2 values
});
var index = col2.indexOf(Math.max.apply(this, col2));
Edit: If you want to use the index of the last found element in case of a tie, use
col2.lastIndexOf(Math.max.apply(this, col2));

The below code will give you the highest number:
var array = [[1, 4, 5],
[2, 6, 7],
[3, 3, 9]];
var bigNum = 0;
for(var i=0;i<array.length; i++){
var largest = Math.max.apply(Math, array[i]);
if(largest > bigNum) {
bigNum = largest;
}
}
console.log(bigNum);

How about this
var arr = [[1, 4, 5], [2, 6, 7], [3, 3, 9]],
t;
$.each(arr, function(k, v){
t = !t ? v[1] : (v[1] > t ? v[1] : t);
});
console.log(t);

Nothing can out better plain loop version, but you can use Array.prototype.reduce like this
var arr = [ [1, 4, 5], [2, 6, 7], [3, 3, 9]], col = 1;
var best = arr.reduce(function(tillNow, current) {
if (tillNow.best < current[col]) {
tillNow.best = current[col];
tillNow.row = current;
}
return tillNow;
}, {best:0, row:[]});
console.log(best.row); # [ 2, 6, 7 ]
console.log(best); # { best: 6, row: [ 2, 6, 7 ] }
Reduce function accepts the till now value as the first parameter and the current element as the second parameter.
For the first element, parameters will be like this
tillNow : {best:0, row:[]} : current: [1, 4, 5]
We compare current's indented column with tillNow.best. If current's is bigger than tillNow, the best element and the current row will be set in tillNow and that will be returned which will be fed back into the reduce's next iteration as tillNow. So, in our case, on the second iteration, values change like this
tillNow : {best:4, row: [1, 4, 5]} : current: [2, 6, 7]
And on third iteration,
tillNow : {best:6, row: [2, 6, 7]} : current: [3, 3, 9]
And finally the result will be
{ best: 6, row: [ 2, 6, 7 ] }

Please try this.
var col2 = [];
var max = 0;
$.each(arr, function(i, val){
col2.push(val[1]);
})
max = Math.max.apply( Math, col2 );

This example returns runs map over over each row and returns an array with the each row's number from the nominated column. It then returns the index of the highest number in that array.
function findRowForMaxInCol(arr, col) {
var column = arr.map(function(el) { return el[col]; });
var highest = Math.max.apply(null, column);
return column.indexOf(highest);
}
console.log(findRowForMaxInCol(arr, 1)); // 1
Fiddle.

Just iterating through the array and checking if the second element is largest. The variable large will contain the row i and the largest value e.
var arr = [ [1, 4, 5],
[2, 6, 7],
[3, 3, 9]],
large = {i:0, e: 0}; // i: row, e: largest elem
arr.map(function (a, idx) {
if (a[1] > large.e) {
large.e = a[1];
large.i = idx;
}
});
console.log(large); // {i: 1, e: 6}. row: 1 and element 6.

Generalizing the problem: find the element in an array which has the maximum 'f(x)':
var findMax = function(array, f){
var element = null;
var max = -Infinity;
for (var i=0; i!=array.length; ++i){
var value = f(array[i]);
if (value > max){
element=array[i];
max=value;
}
};
return element;
};
And apply the general algorithm to rows with a function returning the second element of the row:
var secondElement= function(row){ return row[1]; };
var max = findMax(rows, secondElement);
(JSFiddle)

Related

How to shift all values from an array but remove the last value

I have an array like this :
const arr = [1, 2, 3, 4, 5];
And I want to shift all the values and remove the last value and put 0.
My array should look like this after the operation :
[2, 3, 4, 5, 0]
How to do this ?
here is one approach
const arr = [1, 2, 3, 4, 5];
arr.shift()
arr.push(0)
console.log(arr)
second approach
const arr = [1, 2, 3, 4, 5];
v=arr.slice(1,arr.lenth)
console.log([...v,0])
In case someone finds this useful in java. Note - this approach will manipulate the original array
private void circularArray(int originalArray[]) {
for (int i = 0; i < originalArray.length -1; i++) {
originalArray[i] = originalArray[i+1];
}
originalArray[originalArray.length -1] = 0;
}

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)

Remove minimum value from Array, but if duplicate remove only once

I have the following function which is supposed to remove the smallest value from an array, but if this is a duplicate it will just remove the first one and leave the others.
var array1 = [1, 2, 3, 4, 5];
var array2 = [5, 3, 2, 1, 4];
var array3 = [2, 2, 1, 2, 1];
function removeSmallest(numbers) {
return numbers.filter(function(elem, pos, self) {
if(elem == Math.min.apply(null, numbers) && pos == self.indexOf(elem)) {
// Remove element from Array
console.log(elem, pos);
numbers.splice(pos, 1);
};
return numbers;
});
};
Via console.log(elem, pos) I understand that I have correctly identified the smallest and first element in the array, but when I try to remove it through splice(), I end up getting the following result for the arrays:
array1 = [1, 3, 4, 5]; // But I expected [2, 3, 4, 5]
array2 = [5, 3, 2, 1]; // But I expected [5, 3, 2, 4]
array3 = [2, 2, 1, 1]; // But I expected [2, 2, 2, 1]
Do you know what is the issue with my code? Thanks in advance for your replies!
function removeSmallest(numbers) {
const smallest = Math.min.apply(null, numbers);
const pos = numbers.indexOf(smallest);
return numbers.slice(0, pos).concat(numbers.slice(pos + 1));
};
You shouldn't use filter() the way you do. It's also a good practice that a function should return a new array rather than modifying the existing one and you definitely shouldn't modify an array while iterating over it.
function removeSmallest(arr){
var temp=arr.slice(),smallElement=null;
temp.sort(sortReverse);
smallElement=temp[temp.length-1];
var position=arr.indexOf(smallElement);
arr.splice(pos,1);
console.log(arr);
}
function sortReverse (a,b){
if(a<b){return 1}
else if(a>b){return -1;}
else{return 0;}
}
var array1 = [1, 2, 3, 4, 5];
removeSmallest(array1);

Find the least duplicate items in an array

Okay so as the title says my goal is to find the least duplicate elements, given that the elements are only integers.
ex1: array = [1,1,2,2,3,3,3] result should be 1,2
ex2: array = [1,2,2,3,3,4] result should be 1,4
I could use the xor operator to find the elements that appear only once but since there might be only duplicates I cant.
I was thinking of first checking with XOR if the're any non-duplicate elements. If no proceed with fors to check for only two occurrences of the same element and so on, but that is not a good approach as its kinda slow,
any suggestions?
Another approach, using new Set() and few Array.prototype functions. If you have any questions, let me know.
var array1 = [1, 1, 2, 2, 3, 3, 3],
array2 = [1, 2, 2, 3, 3, 4];
function sort(arr) {
var filtered = [...new Set(arr)],
solution = [],
res = filtered.reduce(function(s, a) {
s.push(arr.filter(c => c == a).length);
return s;
}, []);
var minDupe = Math.min.apply([], res);
res.forEach((v, i) => v == minDupe ? solution.push(filtered[i]) : null)
console.log(solution)
}
sort(array1);
sort(array2);
Using Array#forEach instead of Array#reduce.
var array1 = [1, 1, 2, 2, 3, 3, 3],
array2 = [1, 2, 2, 3, 3, 4];
function sort(arr) {
var filtered = [...new Set(arr)],
solution = [],
res = [];
filtered.forEach(v => res.push(arr.filter(c => c == v).length));
var minDupe = Math.min.apply([], res);
res.forEach((v, i) => v == minDupe ? solution.push(filtered[i]) : null)
console.log(solution)
}
sort(array1);
sort(array2);
There may be a better or faster solution, but I would suggest to create a hash (object) with the integer as keys and the counts as values. You can create this in one loop of the array. Then, loop over the object keys keeping track of the minimum value found and add the key to the result array if it satisfies the minimum duplicate value.
Example implementation:
const counts = input.reduce((counts, num) => {
if (!counts.hasOwnProperty(num)) {
counts[num] = 1;
}
else {
counts[num]++;
}
return counts;
}, {});
let minimums = [];
let minCount = null;
for (const key in counts) {
if (!minimums.length || counts[key] < minCount) {
minimums = [+key];
minCount = counts[key];
}
else if (counts[key] === minCount) {
minimums.push(+key);
}
}
return minimums;
You can also simplify this a little bit using lodash: one operation to get the counts and another to get the minimum count and get the list of values that match that minimum count as a key:
import { countBy, invertBy, min, values } from "lodash";
const counts = countBy(input);
const minCount = min(values(counts));
return invertBy(counts)[minCount];
You could count the appearance, sort by count and delete all same max count keys. Then return the original values.
Steps:
declarate all variables, especial the hash object without any prototypes,
use the items as key got the hash table and if not set use an object with the original value and a count property,
increment count of actual hash,
get all keys from the hash table,
sort the keys in descending order of count,
get the count of the first element and store it in min,
filter all keys with min count,
get the original value for all remaining keys.
function getLeastDuplicateItems(array) {
var hash = Object.create(null), keys, min;
array.forEach(function (a) {
hash[a] = hash[a] || { value: a, count: 0 };
hash[a].count++;
});
keys = Object.keys(hash);
keys.sort(function (a, b) { return hash[a].count - hash[b].count; });
min = hash[keys[0]].count;
return keys.
filter(function (k) {
return hash[k].count === min;
}).
map(function (k) {
return hash[k].value;
});
}
var data = [
[1, 1, 2, 2, 3, 3, 3],
[1, 2, 2, 3, 3, 4],
[4, 4, 4, 6, 6, 4, 7, 8, 5, 5, 6, 3, 4, 6, 6, 7, 7, 8, 3, 3]
];
console.log(data.map(getLeastDuplicateItems));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A single loop solution with a variable for min and an array for collected count.
function getLeastDuplicateItems(array) {
var hash = Object.create(null),
temp = [],
min = 1;
array.forEach(function (a) {
var p = (temp[hash[a]] || []).indexOf(a);
hash[a] = (hash[a] || 0) + 1;
temp[hash[a]] = temp[hash[a]] || [];
temp[hash[a]].push(a);
if (min > hash[a]) {
min = hash[a];
}
if (p === -1) {
return;
}
temp[hash[a] - 1].splice(p, 1);
if (min === hash[a] - 1 && temp[hash[a] - 1].length === 0) {
min++;
}
}, []);
return temp[min];
}
var data = [
[1, 1, 2, 2, 3, 3, 3],
[1, 2, 2, 3, 3, 4],
[4, 4, 4, 6, 6, 4, 7, 8, 5, 5, 6, 3, 4, 6, 6, 7, 7, 8, 3, 3],
];
console.log(data.map(getLeastDuplicateItems));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Remove multiple elements from array by value in JS

When I want to remove one element, it is easy. This is my function:
function removeValues(array, value) {
for(var i=0; i<array.length; i++) {
if(array[i] == value) {
array.splice(i, 1);
break;
}
}
return array;
}
But how do I remove multiple elements?
Here a simple version using ES7:
// removing values
let items = [1, 2, 3, 4];
let valuesToRemove = [1, 3, 4]
items = items.filter((i) => !valuesToRemove.includes(i))
For a simple version for ES6
// removing values
let items =[1, 2, 3, 4];
let valuesToRemove = [1, 3, 4]
items = items.filter((i) => (valuesToRemove.indexOf(i) === -1))
const items = [0, 1, 2, 3, 4];
[1, 4, 3].reverse().forEach((index) => {
items.splice(index, 1)
})
// [0, 2, 4]
I believe you will find the kind of functionality you are looking for in Javascript's built in array functions... particularily Array.map(); and Array.filter();
//Array Filter
function isBigEnough(value) {
return value >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
//Array Map (Can also be used to filter)
var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {
return num * 2;
});
// doubles is now [2, 8, 18]. numbers is still [1, 4, 9]
/////UPDATE REFLECTING REMOVAL OF VALUES USING ARRAY MAP
var a = [1,2,3,4,5,6];
a.map(function(v,i){
if(v%2==0){
a.pop(i);
}
});
console.log(a);
// as shown above all array functions can be used within the call back to filter the original array. Alternativelty another array could be populated within the function and then aassigned to the variable a effectivley reducing the array.

Categories