Sort columns in a matrix - javascript

I have a matrix (or a multidimensional array) of non unique values like this one:
var matrix = [
[1, 3, 2, 4, 1],
[2, 4, 1, 3, 2],
[4, 3, 2, 1, 4]
]
I want to sort a row of this matrix but the others rows should reorder the same in order to keep the column like organization.
//matrix sorted by the row 0
var sorted_matrix = [
[1, 1, 2, 3, 4],
[2, 2, 1, 4, 3],
[4, 4, 2, 3, 1]
]
I would prefer a lodash solution if possible.

You could use an array with the indices and sort it with the values of matrix[0]. Then build a new array with sorted elements.
var matrix = [[1, 3, 2, 4, 1], [2, 4, 1, 3, 2], [4, 3, 2, 1, 4]],
indices = matrix[0].map((_, i) => i);
indices.sort((a, b) => matrix[0][a] - matrix[0][b]);
result = matrix.map(a => indices.map(i => a[i]));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Using lodash you could transpose the matrix with zip, sort it with sortBy by a given row number, and then transpose it back:
_.zip.apply(_, _.sortBy(_.zip.apply(_, matrix), row))
var matrix = [
[1, 3, 2, 4, 1],
[2, 4, 1, 3, 2],
[4, 3, 2, 1, 4]
];
var row = 0;
result = _.zip.apply(_, _.sortBy(_.zip.apply(_, matrix), row));
console.log(result.join('\n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
With the rest parameter syntax you can also write this as:
_.zip(..._.sortBy(_.zip(...matrix), row));

Related

Why is the splice function removing items from the beginning, not the end here? (Javascript)

I'm trying to write a function in Javascript that accepts a nested array and number as two arguments and returns a new nested array with the last couple items removed in each inside array as indicated by the number argument.
For example:
*/ removeColumns([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]], 2);
=> [[1, 2],
[1, 2],
[1, 2],
[1, 2]]
*/
I am attaching the code have written so far. This gives me a return of [[3, 4], [3, 4]. I thought the splice function always removes array elements after the provided index but here it seems to be removing elements before the index. What am I doing wrong here?
const removeColumns = (originalGrid, numColumns) => {
for (let i = 0; i < originalGrid.length; i++) {
console.log(originalGrid[i].splice(originalGrid.length - numColumns, numColumns))
console.log(originalGrid[i])
}
return originalGrid
}
let originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
console.log(removeColumns(originalGrid, 2))
I think that should fix your issue:
originalGrid[i].length - numColumns, numColumns)
In your example
let originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
console.log(originalGrid.length) //2
console.log(originalGrid[0].length) //4
console.log(originalGrid[1].length) //4
So in the loop don't forget to add the index:
console.log(originalGrid[i].splice(originalGrid[i].length - numColumns, numColumns))
Write a filter function. Then, you can choose which column "section" to include.
const originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
const filter = (data, from, to) => data.map(a => a.splice(from, to));
console.log(filter(originalGrid, 0, 2));

Extracting an array with even numbers out a bidimensional set of arrays in javascript

/for the following bidimensional array im trying to write a function that finds the array composed by even numbers and then extract it/
var loggedPasscodes =[
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3]
];
// I can check if its elements are even so:
if(loggedPasscodes[0][1]%2===0) {
console.log(loggedPasscodes[0])
} else {
console.log('nope')
}
//And I can loop the function to atleast give me the outer tier of the array like this:
function getValidPassword(x){
for(i=0;i<x.length;i++){
console.log(x[i])
}
};
console.log(getValidPassword(loggedPasscodes))
I would like to run the function and return the [2, 6, 0, 8] array.
Thanks in advance for your time.
You could find the array by checking each nested array with Array#every and if all values are even.
var loggedPasscodes = [[1, 4, 4, 1], [1, 2, 3, 1], [2, 6, 0, 8], [5, 5, 5, 5], [4, 3, 4, 3]],
allEven = loggedPasscodes.find(a => a.every(v => v % 2 === 0));
console.log(allEven);
If you want more than the first found, you could filter the array.
var loggedPasscodes = [[1, 4, 4, 1], [1, 2, 3, 1], [2, 6, 0, 8], [5, 5, 5, 5], [4, 3, 4, 3]],
allEven = loggedPasscodes.filter(a => a.every(v => v % 2 === 0));
console.log(allEven);
I kept tinkering with the problem and found and alternative answer that runs 2 cycles on the array and displays every 4 consecutive matches. Nina's answer is better and more elegant, but I found this one interesting and i'll leave it here as an alternative.
let loggedPasscodes = [
[4, 3, 4, 4],
[1, 2, 3, 7],
[4, 6, 0, 8],
[2, 2, 2, 2],
[4, 4, 4, 4],
[2, 2, 2, 2],
[1, 3, 4, 5],
[2, 2, 2, 2]
];
function getValidPassword(x){
var password =[];
//main array cycle:
for(ciclop=0;ciclop<x.length;ciclop++){
//secondary array cycle:
for (ciclos=0;ciclos<=4;ciclos++){
//if it gets 4 matches in a row:
if (password.length===4){
console.log(password);
password=[];
}
// if it is even:
else if (x[ciclop][ciclos]%2===0) {
password.push(x[ciclop][ciclos]);
}
//if it is odd:
else if(x[ciclop][ciclos]%2!==0){
password=[];
}
}
}
}
getValidPassword(loggedPasscodes);

Finding closest combination to current ongoing one

I'm currently building a tic tac toe in vanilla javascript. However the game is 'sort of' done but I'm trying to add levels of difficulty. So basically the thing I want to do is , on every player move , to get the the closest possible winning combination based on his moves and place computer's mark into the missing winning's combinations place.
Let's say I have multidimensional array with the winning combinations
winningCombinations: [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 4, 8],
[0, 3, 6],
[1, 4, 7],
[2, 4, 6],
[2, 5, 8]
]
And the player X starts his moves. So his first move is 0, so saving player's current combination in array. So in first move the current comb is
currentPlayerCombintation: [0]
so I want to return [0,1,2], [0,4,8] and [0,3,6] from the winning combination's array.
However the player makes his second move , so he target's 4 so
currentPlayerCombination: [0,4]
and now I want to return the closest possible winning combination which is [0,4,8].
I've tried a lot of things including every() , some() , filter() but could not achieve the thing I want.
I've tried sort of
for(let i = 0; i < this.currentPlayerCombination.length ; i++) {
this.winningCombinations.some((arr) => {
if(arr.includes(this.currentPlayerCombination[i])) {
console.log(arr);
}
});
}
But this didnt work as expected :(
You could take a Set and map the count of the matching items, get the max count and filter the array.
function getWinningPositions(pos) {
var posS = new Set(pos),
temp = winningCombinations.map(a => [a, a.reduce((c, v) => c + posS.has(v), 0)]),
max = Math.max(...temp.map(({ 1: c }) => c))
return temp
.filter(({ 1: c }) => c === max)
.map(([a]) => a);
}
var winningCombinations = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 4, 8], [0, 3, 6], [1, 4, 7], [2, 4, 6], [2, 5, 8]];
console.log(getWinningPositions([0]).map(a => a.join(' ')));
console.log(getWinningPositions([0, 4]).map(a => a.join(' ')));
console.log(getWinningPositions([0, 4, 5]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
First map the winningCombinations to an array of arrays whose numbers are only the numbers that have not been picked yet. Then, find the lowest length of those arrays, and you can identify the original winningCombinations which are closest to the currentPlayerCombination:
const winningCombinations = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 4, 8],
[0, 3, 6],
[1, 4, 7],
[2, 4, 6],
[2, 5, 8]
];
const currentPlayerCombination = [0, 4];
// eg: get [[1, 2], [3, 5,], [6, 7, 8], [8], ...]
const winningCombsWithoutCurrent = winningCombinations.map(arr => (
arr.filter(num => !currentPlayerCombination.includes(num))
));
// eg: here, lowestLength should be 1, because [8] has a length of 1
const lowestLength = winningCombsWithoutCurrent.reduce((a, { length }) => Math.min(a, length), 3);
const combosWithLowestLength = winningCombsWithoutCurrent
.reduce((a, { length }, i) => {
if (length === lowestLength) {
a.push(winningCombinations[i]);
}
return a;
}, []);
console.log(combosWithLowestLength);

Shift entire column in multidimensional array using only javascript or ES6

I have a multidimensional array like below and I want to shift column positions using javascript or ES6 with no jquery or any other plugins.
Eg: Initial array will look like this.
1|2|3|4
2|2|6|4
4|2|3|4
9|2|7|4
How can I shift the 4th column to 1st position so that it will look like this?
4|1|2|3
4|2|2|6
4|4|2|3
4|9|2|7
Could someone can help with logic to shift any columns like this?
You could assing a mapped outer array with new items by slicing the inner arrays with a given index.
For getting the original sort, you could shiftby the delta of length and index.
const shift = (array, index) => array.map(a => [...a.slice(index), ...a.slice(0, index)]);
var array = [[1, 2, 3, 4], [2, 2, 6, 4], [4, 2, 3, 4], [9, 2, 7, 4]],
index = 3;
array = shift(array, index);
console.log(array.map(a => a.join(' ')));
array = shift(array, array[0].length - index);
console.log(array.map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use array.map to re-arrange the values:
function rearrange(rows, pos) {
return rows.map(function(cols) {
return pos.map(function(i) {
return cols[i];
});
});
}
var old_arr;
var new_arr;
old_arr = [
[1, 2, 3, 4],
[2, 2, 6, 4],
[4, 2, 3, 4],
[9, 2, 7, 4]
];
new_arr = rearrange(old_arr, [3, 0, 1, 2]);
console.log(new_arr);
old_arr = [
[1, 2, 3, 4],
[2, 2, 6, 4],
[4, 2, 3, 4],
[9, 2, 7, 4]
];
new_arr = rearrange(old_arr, [3, 2, 1, 0]);
console.log(new_arr);

Convert an Array to unique values only while maintaining the correct sequence

I have the following code:
function uniteUnique(arr) {
//Create a single Array of value
arr = arguments[0].concat(arguments[1], arguments[2]);
//Reduce the Array to unique values only
arr = arr.reduce((pre, curr) => {
//Some function to reduce values
});
return arr;
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
The goal is to produce a single Array containing only unique values while maintaining the order.
Currently it returns:
[1, 3, 2, 5, 2, 1, 4, 2, 1]
I'm wanting to reduce this to:
[1, 3, 2, 5, 4]
You can use Set for that:
function uniteUnique(...args) {
return [...new Set([].concat(...args))];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
It maintains insertion order, and by nature only contains unique values.
In ES5 you could do it by maintaining the used values as properties of a temporary object, while building the result array:
function uniteUnique(/* args */) {
return [].concat.apply([], arguments).reduce(function (acc, v) {
if (!acc[0][v]) acc[0][v] = acc[1].push(v); // assigns new length, i.e. > 0
return acc;
}, [ Object.create(null), [] ])[1];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
You can use the Set object since it already keeps your values unique in one object:
const mySet = new Set([1, 3, 2, 5, 2, 1, 4, 2, 1]);
// returns: Set { 1, 3, 4, 5 };
const arrayUniques = [...mySet];
console.log(arrayUniques);
// returns: [1, 3, 4, 5];

Categories

Resources