How to get largest value in multi-dimensional array - javascript

function largestOfFour(arr) {
var max = 0;
var newArr = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i; j < arr.length; j++) {
max = Math.max(max, arr[i][j]);
}
newArr.push(max);
}
return newArr;
}
Here is my code. It works for me but I want to know is there any other sort way to do this?

Try this:
function largestOfFour(arr) {
return arr.map(function(item){
return Math.max.apply(null, item);
});
}

You may use the spread operator as:
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
const max = Math.max(...data.map(inner => Math.max(...inner)));
console.log(max);

You can try something like this:
Idea, Math.max takes n arguments and gives you the max value. Using .apply you can pass parameters as array. Combining both will give you max value in an array.
Apply
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
var max_arr = data.map(function(a) {
return Math.max.apply(this, a);
});
console.log(max_arr)
Sort + slice + pop
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
var max_arr = data.map(function(a) {
return a.sort().slice(-1).pop()
});
console.log(max_arr)

Related

In a loop that results in several arrays, how to return an array with the sum of all of them

I have an array of strings that, after a lot of effort, I have managed to turn into several arrays with a loop. So right now, the loop is giving me something like:
[4,5,6,7,8]
[4,5,6,7,8],[1,2,3,4,5]
[4,5,6,7,8],[1,2,3,4,5],[22,33,44,55,66]
If I place the return lower in the code, I get:
[[4,5,6,7,8],[1,2,3,4,5],[22,33,44,55,66]]
What I need is the vertical sum of these arrays, so in this case it'd be:
[27,40,53,66,80]
So far, I'm usign '.push'. Also, console.log gives me this answer but return results in 'undefined'. Any help with these two things would be welcome!
----UPDATE----
As someone here suggested, I tried this but it doesn't work entirely:
array=[ [ 1, 2, 4 ], [ 4, 1, 5 ], [ 0, 5, 2 ] ];
let adding=0
const result=[]
for (let i = 0; i < array[0].length; ++i) {
for (let j = 0; j < array.length; ++j) {
adding += array[j][i];
}
result.push(adding);}
console.log(result)
```
The ouput is: [ 5, 13, 24 ] instead of [5,8,11]
1) You can easily achieve the result using map and reduce
const arr = [
[4, 5, 6, 7, 8],
[1, 2, 3, 4, 5],
[22, 33, 44, 55, 66],
];
const result = arr[0].map((_, i) => arr.reduce((acc, curr) => acc + curr[i], 0));
console.log(result)
2) Using simple for loops
const arr = [
[4, 5, 6, 7, 8],
[1, 2, 3, 4, 5],
[22, 33, 44, 55, 66],
];
const result = [];
for (let i = 0; i < arr[0].length; ++i) {
let sum = 0;
for (let j = 0; j < arr.length; ++j) {
sum += arr[j][i];
}
result.push(sum);
}
console.log(result);

JavaScript MinValue

I need find the minimum value from a two-dimensional array.
But something goes wrong, someone can explain me please?
let array = [
[20, 34, 2],
[9, 12, 18],
[3, 4, 5]
];
let str = array.join(",");
console.log(str);
let array_2 = str.split(",");
console.log(array_2);
let minValue = array_2[0];
for (let i = 0; i < array_2.length; i++) {
if (array_2[i] < minValue) {
minValue = array_2[i];
}
}
console.log(minValue);
You need to convert the strings to numbers so that numerical comparison is used instead of lexicographical comparison.
let array = [
[20, 34, 2],
[9, 12, 18],
[3, 4, 5]
];
let str = array.join(",");
console.log(str);
let array_2 = str.split(",").map(Number);//convert to number
console.log(array_2);
let minValue = array_2[0];
for (let i = 0; i < array_2.length; i++) {
if (array_2[i] < minValue) {
minValue = array_2[i];
}
}
console.log(minValue);
Alternatively, you could use Array#flat on the original array so that you do not need to join and split.
let array = [
[20, 34, 2],
[9, 12, 18],
[3, 4, 5]
];
let array_2 = array.flat();
console.log(array_2);
let minValue = array_2[0];
for (let i = 0; i < array_2.length; i++) {
if (array_2[i] < minValue) {
minValue = array_2[i];
}
}
console.log(minValue);
The canonical way is to flatten the array with Array#flat and get the minimum with Math.min by spreading the values (spread syntax ...).
let array = [[20, 34, 2], [9, 12, 18], [3, 4, 5]];
console.log(Math.min(...array.flat()));
Convert your Strings to Number before the comparison
let array = [
[20, 34, 2],
[9, 12, 18],
[3, 4, 5]
];
let str = array.join(",");
console.log(str);
//here you convert to number
let array_2 = str.split(",").map(Number);
console.log(array_2);
Initialize minValue with the highest possible value
you should use Number.MAX_VALUE;
let minValue = Number.MAX_VALUE;
All together
let array = [
[20, 34, 2],
[9, 12, 18],
[3, 4, 5]
];
let str = array.join(",");
console.log(str);
let array_2 = str.split(",").map(Number);
console.log(array_2);
let minValue = Number.MAX_VALUE;
for (let i = 0; i < array_2.length; i++) {
if (array_2[i] < minValue) {
minValue = array_2[i];
}
}
console.log(minValue);

How to convert function in recursion [duplicate]

Could you please tell me how to find all subarray with sum equal to number
Example
arr[] = [2, 4, 45, 6, 0, 19]
x = 51
Output: [2,4,45]
Or
arr[] = [1, 11, 100, 1, 0, 200, 3, 2, 1, 280]
x = 280
Output: [280]
I tried like that but not getting correct output
function getSubArray(arr, num) {
var sum = 0,
blank = [];
var bigArr = []
for (var i = 0; i < arr.length; i++) {
sum = arr[i];
if (blank.length === 0) {
blank.push(arr[i]);
}
for (var j = 1; i < arr.length; j++) {
sum += arr[j];
if (sum < num) {
blank.push(arr[j])
} else if (sum > num) {
sum = 0;
blank = [];
break;
} else {
blank.push(arr[j])
bigArr.push(blank);
sum = 0;
blank = [];
}
}
}
return bigArr
}
console.log(getSubArray([1, 3, 6, 11, 1, 5, 4], 4));
for this expected output is
console.log(getSubArray([1, 3, 6, 11, 1, 5,4],4));
output: [1,3]
[4]
expected output
[[1,3], [4]] is my expected output
You could iterate the array and take either the next element or if no element is taken before omit this element.
function getSubset(array, sum) {
function iter(temp, delta, index) {
if (!delta) result.push(temp);
if (index >= array.length) return;
iter(temp.concat(array[index]), delta - array[index], index + 1);
if (!temp.length) iter(temp, delta, index + 1);
}
var result = [];
iter([], sum, 0);
return result;
}
console.log(getSubset([2, 4, 45, 6, 0, 19], 51)); // [2, 4, 45], [45, 6], [45, 6, 0]
console.log(getSubset([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)); // [280]
console.log(getSubset([1, 3, 6, 11, 1, 5, 4], 4)); // [1, 3], [4]
This might not be exactly what's needed - might require tweaking as the logic may be flawed here.
I have commented the code for clarification.
var arr = [1, 3, 6, 11, 1, 5,4]; // Define array
var target = 31; // Define target
// filter the numbers higher than target and sort rest ascending
var withinRange = arr.filter(x => x <= target).sort((a, b) => a - b);
if(arr.reduce((a,b) => a + b) < target) // Check if we have enough numbers to make up that number
throw "The max you can get out of your selection is: " + arr.reduce((a,b) => a + b);
// grab the highest number as a starting point and remove it from our array of numbers
var numbers = [withinRange.pop()];
var toFind = target - getSum(); // get remainder to find
for(var i = withinRange.length - 1; i > -1; i--) // iterate from the top
{
if(toFind == withinRange[i]){ // check if number is exactly what we need
numbers.push(withinRange[i]);
break;
}else if(withinRange[i] <= toFind){ // if number is smaller than what we look for
numbers.push(withinRange[i]);
toFind -= withinRange[i];
}
}
function getSum(){ // sum up our found numbers
if(numbers.length == 0) return 0;
return numbers.reduce((a,b) => a + b);
}
console.log([numbers, [target]]); // print numbers as desired output
console.log(target, getSum()) // print the target and our numbers
function combinations(array) {
return new Array(1 << array.length).fill().map(
(e1,i) => array.filter((e2, j) => i & 1 << j));
}
function add(acc,a) {
return acc + a
}
combinations([2, 4, 45, 6, 0, 19]).filter( subarray => subarray.reduce(add, 0) == 51 )
output
[[2,4,45],[45,6],[2,4,45,0],[45,6,0]]
combinations([1, 11, 100, 1, 0, 200, 3, 2, 1, 280]).filter( subarray => subarray.reduce(add, 0) == 280 )
output
[[280],[0,280]]
It will give all the available case. And I use the test case of #Nina Scholz
const sum = arr => arr.reduce((a,b) => a + b)
function cal(arr, x) {
const rs = []
for (let i = 0; i< arr.length; i++) {
const tmp = []
for (let j=i; j<arr.length; j++ ) {
tmp.push(arr[j])
if(sum(tmp) === x) rs.push([...tmp])
}
}
return rs
}
console.log(cal([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)) // -> [280]
console.log(cal([2, 4, 45, 6, 0, 19], 51)); // -> [2, 4, 45] [45, 6] [45, 6, 0]
console.log(cal([1, 3, 6, 11, 1, 5, 4], 4)); // -> [1,3] [4]
This will try every possible permutation of the array (will stop further permutations once limit is reached)
function test(arr, num) {
// sorting will improve time as larger values will be eliminated first
arr = arr.sort(function(a, b) {
return b - a;
});
var allLists = [];
var start = Date.now();
helper(0, 0, []);
console.log("Ms elapesed: " + (Date.now() - start));
return allLists || "Not found";
function helper(start, total, list) {
var result = [];
// Using for loop is faster because you can start from desired index without using filter, slice, splice ...
for (var index = start; index < arr.length; index++) {
var item = arr[index];
// If the total is too large the path can be skipped alltogether
if (total + item <= num) {
// Check lists if number was not included
var test = helper(index + 1, total, list.concat(result)); // remove for efficiency
total += item;
result.push(item);
//if (total === num) index = arr.length; add for efficiency
}
}
if (total === num) allLists.push(list.concat(result));
}
}
console.log(test([2, 4, 45, 6, 0, 19], 51)); // [2,4,45] [2,4,45,0] [6,45] [6,45,0]
console.log(test([1, 11, 100, 1, 0, 200, 3, 2, 1, 280], 280)); // [280] [280,0]
If you want to make it more efficient and just return one of the resulted array just comment out the recursive call. You can also un-comment the line that exits the loop once the limit has been reached (will skip 0s).
If the question is about finding all subsets (rather than subarrays) with the given cross sum it is also known as the perfect sum problem.
https://www.geeksforgeeks.org/perfect-sum-problem-print-subsets-given-sum/
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
function printSubsetsRec(arr, i, sum, p)
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if (i == 0 && sum != 0 && dp[0][sum])
{
p.push(arr[i]);
console.log(p);
return;
}
// If sum becomes 0
if (i == 0 && sum == 0)
{
console.log(p);
return;
}
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
var b = p.slice(0);
printSubsetsRec(arr, i-1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i] && dp[i-1][sum-arr[i]])
{
p.push(arr[i]);
printSubsetsRec(arr, i-1, sum-arr[i], p);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
function printAllSubsets(arr, sum)
{
var n = arr.length
if (n == 0 || sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
dp = [];
for (var i=0; i<n; ++i)
{
dp[i] = []
dp[i][0] = true;
}
// Sum arr[0] can be achieved with single element
if (arr[0] <= sum)
dp[0][arr[0]] = true;
// Fill rest of the entries in dp[][]
for (var i = 1; i < n; ++i)
for (var j = 0; j < sum + 1; ++j)
dp[i][j] = (arr[i] <= j) ? dp[i-1][j] ||
dp[i-1][j-arr[i]]
: dp[i - 1][j];
if (dp[n-1][sum] == false)
{
console.log("There are no subsets with sum %d\n", sum);
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
var p = [];
printSubsetsRec(arr, n-1, sum, p);
}
printAllSubsets([1,2,3,4,5], 10);
Solution
'use strict';
function print(arr[], i, j) {
let k = 0;
for (k = i; k <= j; k += 1) {
console.log(arr[k]);
}
}
function findSubArrays(arr[], sum) {
let n = arr.length;
let i;
let j;
let sum_so_far;
for (i = 0; i<n; i+= 1) {
sum_so_far = 0;
for (j = i; j < n; j++) {
sum_so_far += arr[j];
if (sum_so_far === sum) {
print(arr, i, j);
}
}
}
}
I would first loop depending on the size of expected arrays.
After that loop for looking for first part of the array which should be filled with positions that will match the desired number.
For example for x= 4 having arr=[5,4,32,8,2,1,2,2,3,4,4]
It would first take the 4's. Output will start on [ [4], [4], [4], ..... ] for positions 1,9,10 (respectively)
Then go for the arrays resulting sum of 2 elements [ ... [2,2], [2,2],[2,2], [1,3] ...] ( positions 4+6, position 4+7 position6+7 and position 5+8)
You would probably want to use another function to sum and check at this point.
Now will do the same for sum of 3 elements (if any) and so on, having max loop set at number of original array (the resulting number could be the sum of all the elements in the array).
The resulting example would be [ [4], [4], [4], [2,2], [2,2],[2,2], [1,3]]
If the elements would be strictly positive, one could collect such subsequences in a single pass, progressing in a worm/caterpillar-like way: stretching its front in order to grow the sum (when it is bellow the target) and contracting its back in order to lower the sum:
function worm(arr,target){
var ret=[];
var head=0;
var tail=0;
var sum=0;
while(head<arr.length){
while(sum<=target && head<arr.length){
sum+=arr[head++];
if(sum===target)
ret.push(arr.slice(tail,head));
}
while(sum>=target && tail<head){
sum-=arr[tail++];
if(sum===target)
ret.push(arr.slice(tail,head));
}
}
return JSON.stringify(arr)+": "+JSON.stringify(ret);
}
console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));
console.log("But it only occasionally finds 0+... / ...+0 sums:");
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));
One way to deal with the problem related to bounding zeroes is to throw such sequences away. This snippet keeps tail and head(-1) on non-zero elements:
function worm(arr,target){
var ret=[];
var head=0;
while(head<arr.length && arr[head]===0)head++;
var tail=head;
var sum=0;
while(head<arr.length){
while(sum<=target && head<arr.length){
while(head<arr.length && arr[head]===0)head++;
sum+=arr[head++];
if(sum===target)
ret.push(arr.slice(tail,head));
}
while(sum>=target && tail<head){
sum-=arr[tail++];
while(tail<head && arr[tail]===0)tail++;
if(sum===target)
ret.push(arr.slice(tail,head));
}
}
return JSON.stringify(arr)+": "+JSON.stringify(ret);
}
console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26, 0], 51));
console.log(worm([1,8,2], 10));
console.log(worm([0,1,0,8,2,0], 10));
console.log(worm([0,8,2,8,0], 10));
console.log(worm([0,8,0,2,0,8,0], 10));
And the code loses all of its remaining beauty if someone actually needs those 0+... / ...+0 sequences, as they have to be generated in a post-processing step:
function worm(arr,target){
var pairs=[];
var head=0;
while(head<arr.length && arr[head]===0)head++;
var tail=head;
var sum=0;
while(head<arr.length){
while(sum<=target && head<arr.length){
while(head<arr.length && arr[head]===0)head++;
sum+=arr[head++];
if(sum===target)
pairs.push([tail,head]);
}
while(sum>=target && tail<head){
sum-=arr[tail++];
while(tail<head && arr[tail]===0)tail++;
if(sum===target)
pairs.push([tail,head]);
}
}
var ret=[];
for([tail,head] of pairs){
(function pre(tail,head){
ret.push(arr.slice(tail,head));
if(tail>0 && arr[tail-1]===0)
pre(tail-1,head);
(function post(tail,head){
if(head<arr.length && arr[head]===0){
ret.push(arr.slice(tail,head+1));
post(tail,head+1);
}
})(tail,head);
})(tail,head);
}
return JSON.stringify(arr)+": "+JSON.stringify(ret);
}
console.log(worm([2, 4, 45, 6, 19], 51));
console.log(worm([1, 11, 100, 1, 200, 3, 2, 1, 280], 280));
console.log(worm([1, 3, 6, 11, 1, 5, 4], 4));
console.log(worm([2, 4, 45, 6, 0, 19], 51));
console.log(worm([2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26], 51));
console.log(worm([0, 2, 4, 0, 45, 0, 6, 0, 19, 26, 0], 51));
console.log(worm([1,8,2], 10));
console.log(worm([0,1,0,8,2,0], 10));
console.log(worm([0,8,2,8,0], 10));
console.log(worm([0,8,0,2,0,8,0], 10));
I think it works (for non-negative elements), but the first one was simpler for sure.
With map and filter
const arr = [2, 4, 45, 6, 0, 19]
let t = 0
const result = arr.map((v,i)=>{
return [v, t += v]
}).filter((v,i)=>v[1]<=51)
console.log(result)

Iterating over rows of 2-dimensional array containing arrays of different length

I have a function that picks all elements from a 2-dimensional array by its rows and returns a 1-dimensional array.
The array has a variable amount of columns and rows.
Example:
let arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
];
Returns:
[1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12]
The function i came up with:
convertList = (list) => {
let result = [];
let listTotalEntries = R.sum(R.map(R.length)(list));
let mod = R.modulo(R.__, list.length);
let counterRow = -1;
for (let i = 0; i < listTotalEntries; i++) {
if (mod(i) === 0) {
counterRow++;
}
if (list[mod(i)][counterRow]) {
result.push(list[mod(i)][counterRow]);
console.log(list[mod(i)][counterRow]);
}
}
console.log(result);
return result;
};
Question: This function works only with square matrices - how can i make it work with a variable length of the contained arrays?
Example:
let arr = [
[1, 2],
[],
[9, 10, 11, 12]
];
Should return:
[1, 9, 2, 10, 11, 12]
Thanks for your help!
Muff
You had a ramda.js tag in here. With Ramda, it's pretty simple, since there are two functions that will help:
const convertList = compose(flatten, transpose);
convertList(arr); //=> [1, 9, 2, 10, 11, 12]
transpose flips a matrix over its main diagonal, that is, changing rows to columns and vice versa. flatten turns a list of lists into a plain list. So composeing like this essentially creates the equivalent of list => flatten(transpose(list)).
You can see this in action on the Ramda REPL.
I suggest to go step-by-step through the arrays
var arr1 = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
arr2 = [[1, 2], [], [9, 10, 11, 12]];
function single(array) {
var r = [],
max = Math.max.apply(null, array.map(function (a) { return a.length; })),
i = 0, j,
l = array.length;
while (i < max) {
for (j = 0; j < l ; j++) {
i in array[j] && r.push(array[j][i]);
}
i++;
}
return r;
}
document.write('<pre>' + JSON.stringify(single(arr1), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(single(arr2), 0, 4) + '</pre>');
Did you try this simple one?
var singleDimensionArr = arr.reduce(function(prev,current){return prev.concat(current)});
For example
[
[1, 2],
[],
[9, 10, 11, 12]
].reduce(function(prev,current){return prev.concat(current)});
outputs [1, 2, 9, 10, 11, 12]
Edit:
Based on the inputs from OP below, since the concatenation needs to happen column wise
var max = Math.max.apply(null, arr.map(function (a) { return a.length; }));
var finalArr = []; for( var i = 0; i < max; i++)
{
for( var j = 0; j < arr.length; j++)
{
arr[j][i] ? finalArr.push(arr[j][i]) : "";
}
}
console.log(arr);
This example makes a big sparse array putting each item where it would belong if the array were square. Then it filters out null values which occur where no input item was present.
let arr = [
[1, 2],
[],
[9, 10, 11, 12]
];
var out = arr.reduce(function(o,n,i,a) {
for (var j=0;j<n.length;j++){
o[a.length * j + i] = n[j];
}
return o;
},[]).filter(function(n) {
return n !== null;
});
alert(JSON.stringify(out));

Generate JS array that determines sorted rank

Using a complex array (for the use case of tabular data displayed in columns and rows) lets say I have some values:
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
What would be the best way to return a matching array that would rank the values against their column in the correct (maintained) order? The ranked order would be highest to lowest in this case.
For example, an end result array of:
[
[1, 1, 4, 2],
[4, 3, 2, 4],
[3, 4, 1, 3],
[2, 2, 3, 1]
];
Note how the result is sorted vertically by column.
I would want to use this with a large data set, so any guidance/tips for quickest performance is my aim here.
--
For context: My first attempt was to map the original array with the index values, but I was unsure where to go from there:
var singleColumn = [234, -23, 45, 109];
for (var i = 0; i < singleColumn.length; i++) {
singleColumn[i] = [singleColumn[i], i];
}
Essentially the trick will be retaining original indices after the sort. I've iterated them into a data structure first, sorted it, and then rebuilt the 2-dimensional array structure from the result.
I haven't done any checking to ensure that the input is all well-formed, the assumption is all rows are the same width as the first row.
An optimization that could probably be done would be transforming the raw values into the data-structure during the sort, which would eliminate a pass of the array. I don't see an easy way to do that without losing some of the conciseness and readability, and it would be a pretty small gain.
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
function buildRanking(arr) {
var result = [];
for(var col = 0; col < arr[0].length; col++) {
//everything inside this for loop is per column
//first use map function to turn the column into an array of objects
//each holding the value and the current index. [{value: 234, index: 1}, etc..]
var sortableStructure = values.map(function(val, i) {
return { value : val[col], index : i };
});
//Sort function to sort my sortableStructure in place on the values
sortableStructure.sort(function(a, b) {
return b.value - a.value;
});
//now iterate over the sortable strucutre
for(var i = 0; i < sortableStructure.length; i++) {
//this ugly bit just makes sure arrays are initialized for each row as needed
if(typeof result[sortableStructure[i].index] === 'undefined')
result[sortableStructure[i].index] = [];
//for the current item in the sortableStructure, get the index
//access the result element corresponding to that index
//(the original position of this sorted value) and push in
//the current index (sort order) + 1 (to switch from zero-based to one-based)
result[sortableStructure[i].index].push(i + 1);
}
}
return result;
}
//To provide visible output.
document.write(JSON.stringify(buildRanking(values)).split('],[').join('],<br/>['));
First pass at this and highly unoptimized but here's a loose implementation where I do it step by step.
function sort(rows) {
var columns = [];
/* Invert rows and columns */
for (var i = 0, row; i < rows.length; i++) {
row = rows[i];
for (var j = 0, col; j < row.length; j++) {
col = rows[i][j];
columns[j] = columns[j] || [];
columns[j][i] = col;
}
}
/* Sort by descending order, returning index */
var sortedColumns = columns.slice(0).map(function(column, i) {
return column.slice(0).sort(function(a, b) {
return b - a;
}).map(function(value, j, sortedColumn) {
return sortedColumn.indexOf(column[j]) + 1;
});
});
/* Invert rows and columns back again */
var sortedRows = [];
for (var i = 0, row; i < sortedColumns.length; i++) {
row = sortedColumns[i];
for (var j = 0, col; j < row.length; j++) {
col = sortedColumns[i][j];
sortedRows[j] = sortedRows[j] || [];
sortedRows[j][i] = col;
}
}
return sortedRows;
}
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
var expected = [
[1, 1, 4, 2],
[4, 3, 2, 4],
[3, 4, 1, 3],
[2, 2, 3, 1]
];
var sorted = sort(values);
console.log(sorted.toString() === expected.toString()); // true
JSFiddle demo: https://jsfiddle.net/7ek6pz63/2/
Assuming the columns habe to be sorted descending and the result is based on one, then this should work.
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
function getX(array) {
var length = array[0].length,
result = Array.apply(null, { length: array.length }).map(function () { return []; }),
temp, i;
for (i = 0; i < length; i++) {
temp = [];
array.forEach(function (a, j) {
temp.push({ v: a[i], i: j });
});
temp.sort(function (a, b) {
return b.v - a.v;
}).forEach(function (a, j) {
result[a.i][i] = j + 1;
});
}
return result;
}
document.write('<pre>' + JSON.stringify(getX(values), 0, 4) + '</pre>');

Categories

Resources