I have a 2D array:
var array = [["a", "b", "c"],["a", "b", "c"],["a", "b", "c"]]
I want to delete an entire column of this array (i.e. delete every third element within each array).
There are solutions here and here, but neither of them is in javascript, so I'm having trouble relating the situations.
What's the best way to approach this problem? I don't want to use .splice() because in some cases I'll be deleting multiple columns, and the .splice() method will change the length of the array, so I end up accessing out of bounds.
Thanks!
Try using slice. It won't alter any changes to your original array
var array = [["a", "b", "c"],["a", "b", "c"],["a", "b", "c"]]
var x = array.map(function(val) {
return val.slice(0, -1);
});
console.log(x); // [[a,b],[a,b],[a,b]]
This function doesn't use splice and it removes any column you want:
function removeEl(array, remIdx) {
return array.map(function(arr) {
return arr.filter(function(el,idx){return idx !== remIdx});
});
};
Hope this is what you are looking for
Iterate through the array and splice each sub array:
var idx = 2;
for(var i = 0 ; i < array.length ; i++)
{
array[i].splice(idx,1);
}
JSFiddle.
Edit:
I see you don't want to use splice due to out-of-bounds problems and array length changing.
So:
1.You can check if you're out of bounds and skip the slice.
2.You can create an array of indexes you want to delete and simply create new arrays from the indexes that don't appear in that array (instead of deleting, create new arrays with the opposite condition).
Something like this:
var array = [
["a", "b", "c"],
["a", "b", "c"],
["a", "b", "c"]
];
var idxToDelete = [0,2];
for (var i = 0; i < array.length; i++) {
var temp = array[i];
array[i] = [];
for(var j = 0 ; j < temp.length ; j++){
if(idxToDelete.indexOf(j) == -1) // dont delete
{
array[i].push(temp[j]);
}
}
}
New JSFiddle.
use the map function and splice function for your solution. like this
var array = [["a", "b", "c"],["a", "b", "c"],["a", "b", "c"]];
array = array.map(function(item){
// the 0,2 tells the splice function to remove (skip) the last item in this array
return item.splice(0,2);
});
console.log(array);
// [["a", "b"],["a", "b"],["a", "b",]];
don't use delete to delete items from a javascript array. the reason is that delete will toss the item but don't update the internal length variable.
example
var array = ["a", "b", "c"];
delete array[3];
console.log(array);
// ["a", "b"]
console.log(array.length);
// 3
array = array.splice(0,2);
console.log(array);
// ["a", "b"]
console.log(array.length);
// 2
use splice this sets the correct length and delete the item of the array.
You can use filter to remove columns without the need to modify the original array.
var array = [["a", "b", "c"],["a", "b", "c"],["a", "b", "c"]]
var removeIndex = 1
const filtered = array.map(v => v.filter((_, i) => i !== 1))
// output: [["a", "c"], ["a", "c"], ["a", "c"]]
You can also remove multiple columns with the same approach.
var array = [["a", "b", "c"],["a", "b", "c"],["a", "b", "c"]]
var removeIndexes = [0, 2]
const filtered = array.map(v => v.filter((_, i) => !removeIndexes.includes(i)))
// output: [["b"], ["b"], ["b"]]
splice is cool. It resizes the array as it removes things so you don't end up with nulls. So using splice you just have to iterate through each row and remove the right element.
var removeCol = function(arr2d, colIndex) {
for (var i = 0; i < arr2d.length; i++) {
var row = arr2d[i];
row.splice(colIndex, 1);
}
}
http://jsfiddle.net/eB8LD/
Useful code snipped that creates an independent copy of an array
use slice method inside map. Here is an example:
let arrayA = ['a', 'b', 'c', 'd']
let arrayB = arrayA.map((val) => {
return val.slice()
})
arrayB[2] = 'Z';
console.log('--------- Array A ---------')
console.log(arrayA)
console.log('--------- Array B ---------')
console.log(arrayB)
Note: In Angular 10, I used different methods to get an independent copy of an array but all failed. Here are some of them:
arrayB.push(arrayA) // failed
arrayB = Object.create(arrayA) // failed
arrayB = arrayA.splice() // failed
All failed methods were copying references along with data.
Related
So i've been making a website for a store inside my school to get some experience and maybe later on a career as a web dev. Programming the back end of the website was a lot more fun than I expected, until I encountered this issue that i've been debugging for literal hours and have made very little progress on.
I have recreated the situation in a slightly simpler function. Allow me to explain the purposes of everything:
arrayMain: The array that I am intending to sort. It contains more arrays that I wish to sort by the number in the 1 position.
arrayBase: Copy of arrayMain that is intended to never be edited. Mainly used to "unsort" arrayMain if desired.
arrayTemp: A copy of arrayBase that is used in a selection-sort. Repeatedly the item with the lowest number is moved back to arrayMain.
min and transfer: To move over 1 array element, the entirety of arrayTemp is scanned. min starts off as the number in the last item in the list. If a new minimum is detected, it is set to transfer. When all items are checked, arrayTemp[transfer] is moved into arrayMain.
var arrayMain = [["a", 15, "c"], ["a", 18, "c"], ["a", 11, "c"] ,["a", 15, "c"], ["a", 25, "c"]]
var arrayBase = arrayMain.slice(0)
testFunc = function() {
// Clear the main array and prepare to rebuild it in order
arrayMain = []
let arrayTemp = arrayBase.slice(0)
// Length of the array times, find the element with smallest number in position 1 and move it over to arrayMain.
// This is supposed to ignore the last element since that one does not require calculations
for (let i = arrayTemp.length; i > 0; i--) {
let min = arrayTemp[arrayTemp.length - 1][1], transfer = arrayTemp.length - 1
for (let x = (arrayTemp.length - 2); x >= 0; x--) {
if (arrayTemp[x][1] >= min) {
min = arrayTemp[x][1]
transfer = x
}
}
arrayMain.unshift(arrayTemp[transfer])
arrayTemp.splice(transfer, 1)
}
// Move over the last array element and log the results
arrayMain.unshift(arrayTemp[0])
console.log(arrayMain)
}
testFunc()
Expected result:
[ ["a", 11, "c"], ["a", 15, "c"], ["a", 15, "c"], ["a", 18, "c"], ["a", 25, "c"] ]
Actual result:
[ undefined, ["a", 11, "c"], ["a", 15, "c"], ["a", 15, "c"], ["a", 18, "c"], ["a", 25, "c"] ]
I know it's very easy to just remove arrayMain[0], but I want to know if there's a way I can prevent this undefined element from appearing in the first place, or at least know what makes it.
Or, if you have your own way of sorting this that not only works but also does it faster, I guess i'll also accept that, but I really want to know where the undefined is coming from, because if I never figure that out I might end up in this situation again in the future.
Big thanks in advance.
for (let i = arrayTemp.length; i > 0; i--) {
As you insert your last element after the loop, your loop one time too much.
for (let i = arrayTemp.length - 1; i > 0; i--) {
One more logical and readable way may be :
while (arrayTemp.length > 1)
{
// your logic here
}
You loop all items in the outer loop and there you unshift the last item as well.
const
testFunc = function() {
// Clear the main array and prepare to rebuild it in order
arrayMain = [];
let arrayTemp = arrayBase.slice(0)
// Length of the array times, find the element with smallest number
// in position 1 and move it over to arrayMain.
// This is supposed to ignore the last element since that one does not
// require calculations
for (let i = arrayTemp.length; i > 0; i--) {
let min = arrayTemp[arrayTemp.length - 1][1],
transfer = arrayTemp.length - 1;
for (let x = arrayTemp.length - 2; x >= 0; x--) {
if (arrayTemp[x][1] >= min) {
min = arrayTemp[x][1];
transfer = x;
}
}
arrayMain.unshift(arrayTemp[transfer])
arrayTemp.splice(transfer, 1)
}
// Move over the last array element and log the results
// arrayMain.unshift(arrayTemp[0])
console.log(arrayMain);
};
var arrayMain = [["a", 15, "c"], ["a", 18, "c"], ["a", 11, "c"], ["a", 15, "c"], ["a", 25, "c"]]
var arrayBase = arrayMain.slice(0)
testFunc();
.as-console-wrapper { max-height: 100% !important; top: 0; }
To overcome this problem, you need to adjust the start value with length - 1 and take i as index instead of using the length.
const
testFunc = function() {
let arrayMain = [];
let arrayTemp = arrayBase.slice(0),
i = arrayTemp.length;
while (--i) {
let min = arrayTemp[i][1],
transfer = arrayTemp.length - 1,
x = i;
while (x--) {
if (arrayTemp[x][1] >= min) {
min = arrayTemp[x][1];
transfer = x;
}
}
arrayMain.unshift(arrayTemp[transfer])
arrayTemp.splice(transfer, 1)
}
arrayMain.unshift(arrayTemp[0])
console.log(arrayMain);
};
var arrayMain = [["a", 15, "c"], ["a", 18, "c"], ["a", 11, "c"], ["a", 15, "c"], ["a", 25, "c"]]
var arrayBase = arrayMain.slice(0)
testFunc();
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would like to run through every item in a 1D array and perform an indexOf on another 1D array to determine where it matches.
If I have:
Array 1 = ["a","d","e"]
Array 2 = ["a","b","c","d","e","f"]
I would like to transform Array 1 from values into match locations where it would become: [0,3,4].
I tried the equation below, but it didn't work. I thought using forEach() I could go through every item in Array 1. Then I could run a function to perform an indexOf() on Array 2 for each item. What am I doing wrong??
var array1 = ["a","d","e"];
var array2 = ["a","b","c","d","e","f"];
var array1count = array1.forEach( function (e) { array2.indexOf( e )});
Logger.log(array1count)
If array1 has the same order as array2, you could take a closure over the index and use a while loop inside of the callback for mapping found indices.
var array1 = ["a", "d", "e"],
array2 = ["a", "b", "c", "d", "e", "f"],
indices = array1.map((i => v => {
while (array2[++i] !== v) ;
return i;
})(-1));
console.log(indices); // [0, 3, 4]
For not defined order, you neeeither a single loop for gathering the indices and another to map the collected indices.
var array1 = ["a", "d", "e"],
array2 = ["a", "b", "c", "d", "e", "f"],
indices = array1.map(
Map.prototype.get,
array2.reduce((m, v, i) => m.set(v, i), new Map)
);
console.log(indices); // [0, 3, 4]
forEach() returns undefined, you can try using Array.prototype.reduce():
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
var array1 = ["a","d","e"];
var array2 = ["a","b","c","d","e","f"];
var array1count = array2.reduce(function(acc, curr, i) {
if(array1.includes(curr)) //check if the current item is present in array1
acc.push(i);
return acc;
},[]);
console.log(array1count);
I ran this equation and it worked. Seems to be pretty simple and straightforward. Hopefully I'm not missing something here that the other answers are resolving.
var array1 = ["a","d","e"];
var array2 = ["a","b","c","d","e","f"];
var array1count = array1.map( function (item) { return array2.indexOf(item) });
Logger.log(array1count)
How can I pop the random chosen out of the array?
var number = ["a", "b", "c"];
var random = number[Math.floor(Math.random()*number.length)];
use splice
var number = ["a", "b", "c"];
var random = Math.floor(Math.random()*number.length);
console.log(number[random], ' is chosen');
var taken = number.splice(random, 1);
console.log('after removed, ', number);
console.log('number taken, ', taken);
Use splice and the random number as the index.
number.splice(random, 1);
You can use Splice to remove a certain number of items from an array. This method will altar the original array and return the values removed.
The first argument in the Splice method is the starting point. The second argument is the number of items to remove.
Example:
// 0 1 2
var array = ["a", "b", "c"];
var splicedItem = array.splice(1,1);
// The array variable now equals ["a", "c"]
console.log("New Array Value: " + array);
// And the method returned the removed item "b"
console.log("Spliced Item: " + splicedItem);
You can also use a negative number in the first argument to begin counting backwards from the end of the Array.
Example:
// -6 -5 -4 -3 -2 -1
var array2 = ["a", "b", "c", "d", "e", "f"];
var splicedItem2 = array2.splice(-3, 2);
// The array2 variable now equals ["a", "b", "c", "f"]
console.log("New Array Value: " + array2);
// The values removed were "d" and "e"
console.log("Spliced Item: " + splicedItem2);
You can even insert new items into the Array by including additional arguments. You also don't need to return the spliced items to a new variable if you don't want to.
Example:
var array3 = ["a", "b", "c", "d", "e", "f"];
array3.splice(2, 2, "Pink", "Mangoes");
// The array3 value is now ["a", "b", "Pink", "Mangoes", "e", "f"]
console.log("New Array Value: " + array3);
This question already has answers here:
Split array into chunks
(73 answers)
Closed 6 years ago.
I have written a function which takes two parameters: (1) an Array, (2) size of the chunk.
function chunkArrayInGroups(arr, size) {
var myArray = [];
for(var i = 0; i < arr.length; i += size) {
myArray.push(arr.slice(i,size));
}
return myArray;
}
I want to split this array up into chunks of the given size.
chunkArrayInGroups(["a", "b", "c", "d"], 2)
should return: [["a", "b"], ["c", "d"]].
I get back: [["a", "b"], []]
You misunderstood what the slice parameters mean. The second one is the index until which (not included) you want to get the subarray. It's not a length.
array.slice(from, to); // not array.slice(from, length)
function chunkArrayInGroups(arr, size) {
var myArray = [];
for(var i = 0; i < arr.length; i += size) {
myArray.push(arr.slice(i, i+size));
}
return myArray;
}
console.log(chunkArrayInGroups(["a", "b", "c", "d"], 2));
I have a simple bitmask, 3 ("011" in base 2) which denotes that I should extract array[0] and array[1] but not array[2]
What is an efficient way to do this?
Ultimately, I'm generating a new array with values that passed a .filter
Something like this:
var bitmask = 37, // "100101"
array = ["a", "b", "c", "d", "e", "f"];
var array2 = array.filter((value, index) => {
// do something with bitmask and index to return true
});
// array2 should be ["a", "c", "f"];
Expanding on your original example you can do this:
var bitmask = 37, // "100101"
array = ["a", "b", "c", "d", "e", "f"];
var array2 = array.filter((value, index) => {
// do something with bitmask and index to return true
return bitmask & (1 << index);
});
// array2 should be ["a", "c", "f"];
console.log(array2);
var bitmask = 5, idx=0;
// Loop till bitmask reach 0, works when bitmask >= 0
// If you want to sure instead of implicit type converting (from number to boolean)
// Just change it to while(bitmask >= 0)
while(bitmask){
// If the rightmost bit is 1, take the array[index]
if(bitmask & 1) console.log("take arr["+idx+"]");
// Shift right by 1 bit, say 5 = 101, this will make the number become 2 = 10
bitmask>>=1;
// Increase the index
idx++;
}
Using your own example, here is the code works:
var bitmask = 37, // "100101"
array = ["a", "b", "c", "d", "e", "f"],
idx = 0;
var array2 = [];
while(bitmask){
if(bitmask & 1) array2.push(array[idx]);
bitmask>>=1;
idx++;
}
Simply use some bit operation to loop it. As it is looping bit by bit, I think it is the fastest you can get
One way to do this is cast your number into a binary string, then check if the index of the bitmask is "1" inside your filter.
var bitmask = (37).toString(2), // "100101"
array = ["a", "b", "c", "d", "e", "f"];
var array2 = array.filter((value, index) => {
if(bitmask[index] == "1") return value;
});
console.log(array2);