Related
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));
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);
Now I am working on a exercise in freecodecamp. Currently I got an logical error but do not why the failure happens.
In the code,I have to build in a function, which chop the input array based on the parameter. The testing result should be as follows:
chunkArrayInGroups(["a", "b", "c", "d"], 2) should return [["a", "b"], ["c", "d"]].
chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3) should return [[0, 1, 2], [3, 4, 5]].
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4) should return [[0, 1, 2, 3], [4, 5, 6, 7], [8]].
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2) should return [[0, 1], [2, 3], [4, 5], [6, 7], [8]].
And my code are as follows:
function chunkArrayInGroups(arr, size) {
var array = [];
for (var x = 0; x < arr.length ; x+=size){
var spliceArr = arr.splice(0,size);
array.push(spliceArr);
}
array.push(arr);
return array;
}
chunkArrayInGroups(["a", "b", "c", "d","e"], 2);
For most of the conditions, the code works. But for the last condition i.e
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2) should return [[0, 1], [2, 3], [4, 5], [6, 7], [8]].
in this case I cannot get the correct answer. I tested in console log, and turn out the output is like
[[0, 1], [2, 3], [4, 5], [6, 7, 8]].
I know that it is not a difficult question and there are lots of better way to approach it, but can I know what is the logic fallancy in this code?
Many thanks!
Instead of splice use slice. This will also guarantees that the original array is not modified.
Like this (working demo):
function chunkArrayInGroups(arr, size) {
var array = [];
for (var x = 0; x < arr.length; x += size) {
// take elements from current index (`x`) to `x` + `size`
// (do not remove them from the original array, so the original size is not modified either)
var sliceArr = arr.slice(x, x + size);
array.push(sliceArr);
}
return array;
}
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2)); //should return [["a", "b"], ["c", "d"]].
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3)); // should return [[0, 1, 2], [3, 4, 5]].
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4)); // should return [[0, 1, 2, 3], [4, 5, 6, 7], [8]].
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2)); // should return [[0, 1], [2, 3], [4, 5], [6, 7], [8]]
It might help to add a console.log(arr) to your loop to see how the array changes over time.
You would see that it looks like this:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[2, 3, 4, 5, 6, 7, 8]
[4, 5, 6, 7, 8]
Then, take into account your final splice and add which occurs outside of the loop:
[6, 7, 8]
Since your loop increments by size, it will exit once it has gathered all subarrays of exactly size.
Instead, I would recommend continuing until your input is empty:
function chunkArrayInGroups(arr, size) {
var array = [];
while(arr.length > 0){
var spliceArr = arr.splice(0,size);
array.push(spliceArr);
}
return array;
}
You will want to step using the size to save on the number of loops through the array. We are also saving the length so it's not fetched each time as it saves operations. Also you will notice that I'm not using var as you shouldn't be using it. Please use let for normal variables and const for variables you are not going to reassign.
function chunkArrayInGroups(arr, size) {
let array = [];
let arrayLength = arr.length;
for (let i = 0; i < arrayLength; i+=size) {
array.push(arr.slice(i, i+size));
}
return array
}
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2), [["a", "b"], ["c", "d"]])
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]])
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4), [[0, 1, 2, 3], [4, 5, 6, 7], [8]])
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2), [[0, 1], [2, 3], [4, 5], [6, 7], [8]])
The issue here is that you are reducing the array length throughout your iteration. I.e. your array gets smaller within each iteration while your x continously increases. That means that before your last iteration your x will be at 6 and the array length will be 3, hence x < arr.length evaluates to false and your last iteration does not happen. The most simplistic solution that I can think of is to store the original array length into a variable I named stop and remove the unneccessary final array push outside the loop.
function chunkArrayInGroups(arr, size) {
var array = [];
var stop = arr.length;
for (var x = 0; x < stop; x+=size){
var spliceArr = arr.splice(0,size);
array.push(spliceArr);
}
return array;
}
console.log(chunkArrayInGroups([1,2,3,4,5,6,7], 2))
splice method changes the length of array on every iteration. That's why your loop exits before you expect. You can read more about splice here.
Unlike splice, slice will not remove items from the array that's why lealceldeiro answer will work as expected.
Kevin Bruccoleri answer looks cleaner and shorter but if you have an app where you store an array in to a variable and then pass it to the function, that variable will be empty after the execution of the function, which can lead to bugs in your app. That's why arrays are basically object, but that's science fiction of javascript.
function chunkArrayInGroups(arr, size) {
var array = [];
while (arr.length) {
array.push(arr.splice(0, size))
}
return array
}
var nums = [0, 1, 2, 3, 4, 5, 6, 7, 8]
console.log('now it full', nums);
console.log(chunkArrayInGroups(nums, 2));
console.log('now it empty', nums);
Used slice to copy original array two
map() and splice() to insert array from n index
const frankenSplice = (arr1, arr2, n) => {
let arr = arr2.slice();
arr1.map(e => {
arr.splice(n, 0, e);
n++;
})
return arr;
}
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));
How to simply flatten array in jQuery? I have:
[1, 2, [3, 4], [5, 6], 7]
And I want:
[1, 2, 3, 4, 5, 6, 7]
You can use jQuery.map, which is the way to go if you have the jQuery Library already loaded.
$.map( [1, 2, [3, 4], [5, 6], 7], function(n){
return n;
});
Returns
[1, 2, 3, 4, 5, 6, 7]
Use the power of JavaScript:
var a = [[1, 2], 3, [4, 5]];
console.log( Array.prototype.concat.apply([], a) );
//will output [1, 2, 3, 4, 5]
Here's how you could use jquery to flatten deeply nested arrays:
$.map([1, 2, [3, 4], [5, [6, [7, 8]]]], function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs): n);
});
Returns:
[1, 2, 3, 4, 5, 6, 7, 8]
Takes advantage of jQuery.map as well as jQuery.isArray.
var a = [1, 2, [3, 4], [5, [6, [7, 8]]]];
var b = [];
function flatten(e,b){
if(typeof e.length != "undefined")
{
for (var i=0;i<e.length;i++)
{
flatten(e[i],b);
}
}
else
{
b.push(e);
}
}
flatten(a,b);
console.log(b);
The flatten function should do it, and this doesn't require jQuery. Just copy all of this into Firebug and run it.
To recursively flatten an array you can use the native Array.reduce function. The is no need to use jQuery for that.
function flatten(arr) {
return arr.reduce(function flatten(res, a) {
Array.isArray(a) ? a.reduce(flatten, res) : res.push(a);
return res;
}, []);
}
Executing
flatten([1, 2, [3, 4, [5, 6]]])
returns
[ 1, 2, 3, 4, 5, 6 ]
You can use jQuery.map():
callback( value, indexOrKey )The function to process each item
against. The first argument to the function is the value; the second
argument is the index or key of the array or object property. The
function can return any value to add to the array. A returned array
will be flattened into the resulting array. Within the function, this
refers to the global (window) object.
Use recursion if you have multiple levels:
flaten = function(flatened, arr) {
for(var i=0;i<arr.length;i++) {
if (typeof arr[i]!="object") {
flatened.push(arr[i]);
}
else {
flaten(flatened,arr[i]);
}
}
return;
}
a=[1,[4,2],[2,7,[6,4]],3];
b=[];
flaten(b,a);
console.log(b);
You can use Array.prototype.reduce which is technically not jQuery, but valid ES5:
var multidimensionArray = [1, 2, [3, 4], [5, 6], 7];
var initialValue = [];
var flattened = multidimensionArray.reduce(function(accumulator, current) {
return accumulator.concat(current);
}, initialValue);
console.log(flattened);
Old question, I know, but...
I found this works, and is fast:
function flatten (arr) {
b = Array.prototype.concat.apply([], arr);
if (b.length != arr.length) {
b = flatten(b);
};
return b;
}
You need arr.flat([depth])
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]