Check if a JavaScript 2D array is in ascending order? - javascript

Suppose I have an array as such
var arr = [ [1,2,3],[4,5,1]]
How do I check if the columns are in ascending order?
For first column 1<4 returns true but the last column returns false as 3 is not less than 1.
The result should return an array of the columns that returns false

I would do it by first transposing the matrix (simply because its easier to deal with in js) and then map over each column (converting them from a set of numbers into a bool using Array#every).
const arr = [
[1,2,3],
[4,5,1]
];
const transpose = (arr) => Array(arr[0].length)
.fill(0)
.map((_, colIndex) => {
return Array(arr.length)
.fill(0)
.map((_, rowIndex) => {
return arr[rowIndex][colIndex];
});
});
const arr2 = transpose(arr);
const arr3 = arr2.map(col => {
let previousValue = -Infinity;
return col.every(v => {
const tmp = previousValue < v;
previousValue = v;
return tmp;
});
});
console.log(arr);
console.log(arr2);
console.log(arr3);

One possible solution is to use Array.map() over the first inner array, and then check if you found some element on a particular column that is not in order using Array.some():
var arr = [
[1, 2, 3],
[4, 5, 1],
[6, 7, 2]
];
let res = arr[0].map((n, cIdx) =>
{
return !arr.some((inner, rIdx) => rIdx > 0 && inner[cIdx] < arr[rIdx - 1][cIdx]);
});
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

To find the "columns" with the two values in descending order, you can use parallel arrays. Here is a succinct version of the code for that. (The second snippet is more verbose and provides further explanation.)
var arr = [ [1,2,3], [4,5,1] ], result = [];
arr[0].forEach((n, i) => { // n is the number, i is the index
if(arr[0][i] > arr[1][i]){ result.push(i); } // if descending, remember this index
});
console.log(result); // Logs `[2]` (an array with the index of the third column)
If you want to change which "column" the values are in so that they will be in ascending order, you could do it like this. When you find a "misplaced" value, store it in a temporary variable to make room. Then you can assign the two values to their "correct" locations.
const bigArr = [ [1,2,3], [4,5,1] ],
a1 = bigArr[0],
a2 = bigArr[1],
resultArr = [],
len = Math.min(a1.length, a2.length); // Uses min in case they have different lengths
for(let i = 0; i < len; i++){
if(a1[i] > a2[i]){ // Checks each position, and exchanges values if necessary
exchangeValuesInParallelArrays(a1, a2, i);
resultArr.push(i); // Adds this index to the results array
}
}
console.log(bigArr); // Logs `[ [1,2,1], [4,5,3] ]`
console.log(resultArr) // Logs `[2]`
function exchangeValuesInParallelArrays(arr1, arr2, index){
let tempStorage = arr1[index];
arr1[index] = arr2[index];
arr2[index] = tempStorage;
}

Related

How to sort 2 dimensional array (matrix) in JavaScript?

I want to sort a 2 dimensional array of integers. What is the simplest and most readable way to achieve this?
input:
[
[3,4,2],
[5,1,3],
[2,6,1],
]
output:
[
[1,1,2],
[2,3,3],
[4,5,6]
]
If you'd need the deeper arrays to be in order as well, I'd tackel it like so:
Flatten the arrays using flat(), so get just a regular list
input.flat()
Sort them using a custom integer sort function
.sort((a, b) => a - b)
Re-create the second dimension
array_chunks(sortedArray, 3);
(Function used taken from this answer)
const input = [
[3,4,2],
[5,1,3],
[2,6,1],
];
const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));
let result = array_chunks(input.flat().sort((a, b) => a - b), 3);
console.log(result);
[
[ 1, 1, 2 ],
[ 2, 3, 3 ],
[ 4, 5, 6 ]
]
When working with nested arrays, its common to work from the inner most level and then step out. Using this method, we start with the inner arrays:
// Sorting the inner most array
var result = [];
[
[3,4,2],
[5,1,3],
[2,6,1],
].forEach(function(row) { // a for loop could work as well, this is just shorter.
result.push(row.sort(function(a, b) {
return a-b; // ascending
// return b-a; // descending
}));
});
Then, you sort the outer array. You cannot sort the outer array as a single number, so its necessary to decide on a method. Examples being: average of the array, lowest value, or highest value.
// Using the first value to sort the outer array.
[
[2,3,4],
[1,3,5],
[1,2,6],
].sort(function(a, b) {
return a[0]-b[0];
});
Alternatively
The wanted output "[[1,1,2],[2,3,3],[4,5,6]]" disregards the inner arrays so it doesn't seem practical. To do this however, we'd reconstruct all inner arrays into one, sort, and then rebuild a nested array assuming each new array is to have 3 values.
var oneDimensionalArray = [];
var finalArray = [];
[
[3,4,2],
[5,1,3],
[2,6,1],
].forEach(function(row) {
oneDimensionalArray = oneDimensionalArray.concat(row);
});
oneDimensionalArray.sort();
for (var i=0; i<oneDimensionalArray.length; i++) {
if (i%3==0) {
temp = [];
}
temp.push(oneDimensionalArray[i]);
if (i%3==2) { // 3 per line (0-2)
finalArray.push(temp);
}
}
Again, I don't see this having practical usefulness. It would be easier to leave them as a regular array or start with a different setup if all the data is to be used in a way that disregards grouping/array.
This is a general approach of nested array, which could have more nested arrays or different lengths.
It works by taking an array of indices to every value, a flat array of values and finally by assigning all values back to their place.
const
getIndices = (value, index) => Array.isArray(value)
? value.flatMap(getIndices).map(array => [index, ...array])
: [[index]],
setValue = (array, keys, value) => {
const last = keys.pop();
keys.reduce((a, i) => a[i] ??= [], array)[last] = value;
return array;
};
data = [[3, 4, 2], [5, 1, 3], [2, 6, 1]],
references = data.flatMap(getIndices),
result = data
.flat()
.sort((a, b) => a - b)
.reduce((r, v, i) => setValue(r, references[i], v), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Find indices of all duplicate records in js

Suppose I have an array as below:
Arr1 = [12,30,30,60,11,12,30]
I need to find index of elements which are repeated in array e.g.
ans: 0,1,2,5,6
I've tried this code but it is considering just single element to check duplicates.
First get all the duplicates using filter() and then using reduce() get he indexes of only those elements of array which are in dups
const arr = [12,30,30,60,11,12,30];
const dups = arr.filter(x => arr.indexOf(x) !== arr.lastIndexOf(x));
const res = arr.reduce((ac, a, i) => {
if(dups.includes(a)){
ac.push(i)
}
return ac;
}, []);
console.log(res)
The time complexity of above algorithm is O(n^2). If you want O(n) you can use below way
const arr = [12,30,30,60,11,12,30];
const dups = arr.reduce((ac, a) => (ac[a] = (ac[a] || 0) + 1, ac), {})
const res = arr.reduce((ac, a, i) => {
if(dups[a] !== 1){
ac.push(i)
}
return ac;
}, []);
console.log(res)
You could use simple indexOf and the loop to get the duplicate indexes.
let arr = [12,30,30,60,11,12,30]
let duplicate = new Set();
for(let i = 0; i < arr.length; i++){
let index = arr.indexOf(arr[i], i + 1);
if(index != -1) {
duplicate.add(i);
duplicate.add(index);
}
}
console.log(Array.from(duplicate).sort().toString());
A slightly different approach with an object as closure for seen items which holds an array of index and the first array, in which later comes the index and a necessary flattening of the values.
This answer is based on the question how is it possible to insert a value into an already mapped value.
This is only possible by using an object reference which is saved at the moment where a value appears and which is not seen before.
Example of unfinished result
[
[0],
[1],
2,
[],
[],
5,
6
]
The final Array#flat removes the covering array and shows only the index, or nothing, if the array remains empty.
[0, 1, 2, 5, 6]
var array = [12, 30, 30, 60, 11, 12, 30],
indices = array
.map((o => (v, i) => {
if (o[v]) { // if is duplicate
o[v][1][0] = o[v][0]; // take the first index as well
return i; // return index
}
o[v] = [i, []]; // save index
return o[v][1]; // return empty array
})({}))
.flat() // remove [] and move values out of array
console.log(indices);
You could use Array#reduce method
loop the array with reduce.At the time find the index of argument
And check the arguments exist more than one in the array using Array#filter
Finaly push the index value to new accumulator array.If the index value already exist in accumalator.Then pass the currentIndex curInd of the array to accumulator
const arr = [12, 30, 30, 60, 11, 12, 30];
let res = arr.reduce((acc, b, curInd) => {
let ind = arr.indexOf(b);
if (arr.filter(k => k == b).length > 1) {
if (acc.indexOf(ind) > -1) {
acc.push(curInd)
} else {
acc.push(ind);
}
}
return acc;
}, []);
console.log(res)
Below code will be easiest way to find indexes of duplicate elements
var dupIndex = [];
$.each(Arr1, function(index, value){
if(Arr1.filter(a => a == value).length > 1){ dupIndex.push(index); }
});
This should work for you

how to iterate array of array in javascript to get common item ?

/*1 2 3
2 1 3
2 3 1 */
var arr = [
[1,2,3],
[2,1,3],
[2,3,1]
]
function commonElementInColumn(arr){
var a = arr[0],
b=false,
commItem =[];
for(var i=0 ; i<a.length ;i ++){
var item = a[i];
for(j=1; j< arr.length ; j++){
if(arr[j].indexOf(item) !==-1){
b =true
}else {
b= false
}
}
if(b){
commItem.push(item)
}
}
return commItem
}
console.log(commonElementInColumn(arr))
I am trying to find common column item in matrix .I tried like this. But not getting expected output .I am getting [1,2,3] but
can we add any logic which find common element in columns
Expected output is [1]
Let take I have m x n matrix .I want to find common element which is present in all coloum.
See input
/*1 2 3
2 1 3
2 3 1 */
1 is present in all three column.
2 is present only first and second not in third
3 is present on second and third but not in first
Try following
var arr = [
[1,2,3], [2,1,3], [2,3,1]
];
// Create the map of items with value to be an array of indexes
var map = {};
var result = [];
// iterate over the array
arr.forEach(function(subArray){
subArray.forEach(function(item, index){
map[item] = map[item] ? map[item] : [];
// if the map has the item and the index already exists in the array, skip
if(!map[item].includes(index)) {
map[item].push(index);
}
// if the length is same as the array item length (assuming same for all subArray's) then it means all indexes have been covered
if(map[item].length === arr[0].length) {
result.push(item);
}
});
});
console.log(result);
A slightly different approach with a Map for the values and a Set for each value for collecting the indices. Later check the size of the sets and take the keys of the map as result arrray.
function commonCol(array) {
var map = new Map;
array.forEach(a => a.forEach((v, i) => {
if (!map.has(v)) {
map.set(v, new Set);
}
map.get(v).add(i);
}));
return Array
.from(map.entries())
.filter(({ 1: v }) => v.size === array[0].length)
.map(([k]) => k);
}
var array = [[1, 2, 3], [2, 1, 3], [2, 3, 1]];
console.log(commonCol(array));
Take a look at that:
var arr = [
[1,2,3],
[2,1,3],
[2,3,1]
]
// Creates another array from arr organized by column
var byColumn = arr.reduce((accumulator, item) => {
item.forEach((element, index) => {
if(!accumulator[index]) accumulator[index] = [];
accumulator[index].push(element);
});
return accumulator;
}, [])
// Gets the first array of arr to iterate
var firstArray = arr[0];
// Gets an array of elements that appears in all columns
var filteredNumbers = firstArray.filter(element => {
return byColumn.every(item => item.includes(element));
});
console.log(filteredNumbers); // [1]
Use Array#filter() on first subarray since it must contain any common values.
Within that filter use a Set to pass all indices for each number to. Since a Set must have unique values you can then check it's size and if it matches subarray length then all indices are unique
var arr = [
[1, 2, 3],
[2, 1, 3],
[2, 3, 1]
]
function commonElementInColumn(arr) {
// return filtered results from first subarray since it has to contain any common values `
return arr[0].filter((num) => {
// get all indices for this number as array
let indices = arr.map(subArr => subArr.indexOf(num));
//create a set from this array which will void duplicates
let uniqueIndices = new Set(indices);
// if size of set is same as subarray length then all indices for this number are unique
return uniqueIndices.size === arr[0].length;
});
}
console.log(commonElementInColumn(arr))

Sort two arrays based on the length of one

I have two arrays and the data is combined, like:
[maximilian,moritz,hans] and
[5,1,2000]
Now I have to sort the first array based on the length of the names and keep the numbers at the right spot. The result should be:
[hans,moritz,maximilian]
[2000,1,5]
Normally you can combine both arrays, sort them and then separate them. Simple. But in my case the numbers have different lengths, so the right ordering isn't guaranteed.
If i combine and sort then, the result gonna be:
[moritz,hans,maximilian]
[1,2000,5]
and this is wrong.
Anyone has an idea how to fix this?
You could take the indices, sort them and map the values for both arrays.
var array1 = ['maximilian', 'moritz', 'hans'],
array2 = [5, 1, 2000],
indices = array1.map((_, i) => i);
indices.sort((a, b) => array1[a].length - array1[b].length);
array1 = indices.map(i => array1[i]);
array2 = indices.map(i => array2[i]);
console.log(array1);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Create a single array of objects in the form of
var array = [{name: hans, number: 2000}, {name: moritz, number: 1}, {name: maximilian, number: 5}];
Then you can sort by the key name without having to worry about the numbers
You can also use Map to sort both arrays:
let a1 = ['maximilian', 'moritz', 'hans'],
a2 = [5, 1, 2000];
(map => {
a1.sort(({length:s1}, {length:s2}) => s1 - s2);
a2 = a1.map(s => map.get(s));
})(new Map(a1.map((v, i) => [v, a2[i]])));
console.log(a1);
console.log(a2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Docs:
Map
Array.prototype.sort()
Array.prototype.map()
Object Destructuring
Arrow Functions
I would make an array of objects, combining both arrays into one, then sort them by key, and then splitting them again.
const arr1 = [ 'maximilian', 'moritz', 'hans' ]
const arr2 = [5, 1, 2000]
const tmp = [];
for (let i = 0; i < arr1.length; i++) {
tmp.push({ key: arr1[i], val: arr2[i] });
}
tmp.sort((a, b) => a.val < b.val);
console.log(tmp);
const keys = tmp.reduce((sub, elem) => { sub.push(elem.key); return sub }, []);
const vals = tmp.reduce((sub, elem) => { sub.push(elem.val); return sub }, []);
console.log(keys);
console.log(vals);

Sorting a numeric array along with an array of objects in JavaScript

Suppose I generate two arrays
One that holds Array of numbers:
[5.65, 3.25, 4.34, 6.78]
And another array that holds objects with some information in them
[car.object1, car.object2, car.object3, car.object4]
And the objects in second array are related to the numbers in first array. So object1 is related to 5.65, object2 to 3.25 and so on.
So I want to sort the array 1 in an ascending order and at the same time sort the array 2 also.
So the result should be:
[3.25, 4.34, 5.65, 6.78]
&
[car.object2, car.object3, car.object1, car.object4]
My Approach: (You can just ignore the below answer as I think it is wrong. It does not work.)
var all = [];
var A = [5.65, 3.25, 4.34, 6.78];
var B = ['store.object1', 'store.object2', 'store.object3', 'store.object4'];
for (var i = 0; i < B.length; i++) {
all.push({
'A': A[i],
'B': B[i]
});
}
all.sort(function(a, b) {
return a.A - b.A;
});
A = [];
B = [];
for (var i = 0; i < all.length; i++) {
A.push(all[i].A);
B.push(all[i].B);
}
console.log(A, B);
You could use a temporary array with the indices and sort it with the values of the first array. Then map the sorted array with the values of array1 and array2.
I use strings for the second array, instead of missing objects.
var array1 = [5.65, 3.25, 4.34, 6.78],
array2 = ['car.object1', 'car.object2', 'car.object3', 'car.object4'],
temp = array1.map(function (_, i) { return i; });
temp.sort(function (a, b) { return array1[a] - array1[b]; });
array1 = temp.map(function (a) { return array1[a]; });
array2 = temp.map(function (a) { return array2[a]; });
console.log(temp);
console.log(array1);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Unless you want to implement the sort yourself, one simple way is to combine the entries from the number array with the entries from the object array (at least briefly), sort that, and then (if necessary) extract the result:
// Setup
var car = {
object1: {name: "object1"},
object2: {name: "object2"},
object3: {name: "object3"},
object4: {name: "object4"}
};
var nums = [5.65, 3.25, 4.34, 6.78];
var objs = [car.object1, car.object2, car.object3, car.object4];
// Combine
var joined = [];
nums.forEach(function(num, index) {
joined[index] = {num: num, object: objs[index]};
});
// Sort
joined.sort(function(a, b) {
return a.num - b.num;
});
// Extract
nums = [];
objs = [];
joined.forEach(function(entry, index) {
nums[index] = entry.num;
objs[index] = entry.object;
});
console.log(nums);
console.log(objs);
.as-console-wrapper {
max-height: 100% !important;
}
But rather than combine, sort, and extract, I'd probably just maintain a single array and add each number to its relevant object, so they always travel together.
Here is an ES6 way to do it:
let a = [5.65, 3.25, 4.34, 6.78];
let b = [{ x:1 }, { x:2 }, { x:3 }, { x: 4}];
[a, b] = a.map( (n, i) => [n, b[i]] ) // zip the two arrays together
.sort( ([n], [m]) => n-m ) // sort the zipped array by number
.reduce ( ([a,b], [n, o]) => [[...a, n], [...b, o]], [[],[]] ); // unzip
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
I've helped myself with an object containing car.object as the key and it's number as the value. Seems easy&quick solution.
var obj = [{'car.object1': 5.65}, {'car.object2': 3.25}, {'car.object3': 4.34}, {'car.object4': 6.78}],
objs = obj.sort((a,b) => a[Object.keys(a)] - b[Object.keys(b)]);
console.log(objs.map(v => Object.keys(v)[0]));
console.log(objs.map(v => v[Object.keys(v)]));
console.log(objs);
.as-console-wrapper {
max-height: 100% !important;
}

Categories

Resources