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);
Related
I am new to JavaScript. Can anyone tell me why counter = 1 is added in following code ?
function count(string) {
let string1 = string.split("").sort().join("");
let counter = 1;
for (let i = 0; i < string1.length; i++) {
if (string1[i] == string1[i + 1]) {
counter++;
} else {
console.log(string1[i] + " " + counter);
counter = 1;//-----------> this one
}
}
}
count("amanpreetsaingh");
You sort the whole characters in the string and start from left to right.
If your string is amanpreetsaingh, it becomes aaaeeghimnnprts.
Now what you do is keep a counter=1 starting from index 0. And check for every letter you check if it is equal to the next one, if yes then we are counting for the same letter and increase counter (like in case of the first two as). Once we reach the last a, our next letter (e) is not the same as our current letter, so we log our current value and reset count.
you can simply use reduce function:
reduce it's an array method so make sure to transform your string into array by using split(""):
text.split("") // ["a", "a", "a", "a", "b", "b", "b", "c", "c", "c", "c", "c", "c", "c", "d", "d", "d", "d", "d", "d", "d"]
then apply reduce on the result array :
text.split("").reduce((acc, c) => {
const counter = acc[c] || 0;
return {
...acc,
[c]: counter + 1,
};
}, {}); // { a: 4, b: 3, c: 6, d: 5 }
I suggest you watch this series of videos about the arrays method from ack Herrington: https://youtu.be/NaJI7RkSPx8
i have a long list of sets of elements of varied amounts . For each line, I want to extract only those sets which have 4 elements or more and push them into a separate array . If the set has more than 4 elements , I want to extract each set of 4 elements within them. for instance
a,b,c
a,b,c,d
d,b,c,a
a,b,d,c,a,d
a,d
returns
result = [ [a,b,c,d], [d,b,c,a] , [a,b,d,c], [b,d,c,a], [d,c,a,d] ]
notice that the second to the last set of elements produces 3 arrays at the end of the result array.
How would i write a JS or Ruby function/method to return this kind of result ??
A Ruby solution: first select the arrays which are big enough, then put all consecutive series of 4 elements in the result.
input = [['a','b','c'], ['a','b','c','d'], ['d','b','c','a'], ['a','b','d','c','a','d'], ['a','d']]
p input.select{|ar| ar.size >= 4}.flat_map{|ar| ar.each_cons(4).to_a }
# =>[["a", "b", "c", "d"], ["d", "b", "c", "a"], ["a", "b", "d", "c"], ["b", "d", "c", "a"], ["d", "c", "a", "d"]]
Here is the solution, I looked at the array if it is length of 4 I just pushed it into the result if it is more then 4 then I iterated over it to push every one instance of 4, I hope this is what you wanted.
const input = [['a','b','c'], ['a','b','c','d'], ['d','b','c','a'], ['a','b','d','c','a','d'], ['a','d']]
const result = []
input.forEach(arr => {
if (arr.length === 4) {
result.push(arr)
} else if (arr.length > 4) {
for (let i = 0; i < arr.length - 3; i++) {
result.push(arr.slice(0 + i, 4 + i))
}
}
})
console.log('result = ', result)
//result = [ [a,b,c,d], [d,b,c,a] , [a,b,d,c], [b,d,c,a], [d,c,a,d] ]
Another Ruby solution.
input = [['a','b','c'], ['a','b','c','d'], ['d','b','c','a'],
['a','b','d','c','a','d'], ['a','d']]
input.each_with_object([]) do |a,arr|
a.each_cons(4) { |a4| arr << a4 } if a.size > 3
end
#=> [["a", "b", "c", "d"], ["d", "b", "c", "a"], ["a", "b", "d", "c"],
# ["b", "d", "c", "a"], ["d", "c", "a", "d"]]
See Enumerable#each_cons.
let's assume that we have two arrays like these:
let s1 = ["A", "B", "C", "D", "B"] // Note: "B" has been occurred 2 times
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"] // // Note: "B" has been occurred 2 times just like s1 but we have another occurrence for "A"
I want to create a new array (let s3) based on these two arrays with this rule that we'll remove the element(s) with occurrences more than the same element's occurrence in array s1
so the s3 array would be like this:
let s3 = ["A", "B", "C", "D", "B", "X", "Y"] // we just removed "A" cause it occurred more than "A" occurances in s1
Note that we want anything else ("X", "Y"). we just want to handle the extra occurrences.
so far I can find the index of repeated occurrences like this but I can't find a way to compare each occurrence to see if it is an extra one or not (complicated):
let s1 = ["A", "B", "C", "D", "B"]
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"]
var s3 = [];
for (let i = 0; i < s2.length; i++) {
for (let j = 0; j < s1.length; j++) {
if (s2[i] === s1[j]) {
s3.push(i);
break;
}
}
}
console.log(s3)
My English is poor and I don't know if I could explain the issue or not!
Note: I can simply use s3 = [...new Set(s2)] to remove repeated elements but I want something else.
Since you want to keep everything originally in s1 but only add items from s2 if they aren't already in you can initially set s3 to s1. Then loop over s2 and if s1 does not have the value then push it into s3.
const s1 = ["A", "B", "C", "D", "B"];
const s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"];
const s3 = [...s1];
s2.forEach(d => {
if (!s1.includes(d)) s3.push(d);
});
console.log(s3);
You can use Map and filter
First Map the array1 to [key, value] format
Iterate over second array, if it's found in Map and value is grater than zero return true else return false,
If it is not found return true
let s1 = ["A", "B", "C", "D", "B"]
let s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"]
let map = new Map()
s1.forEach(v=>{
if(map.has(v)){
map.set(v,map.get(v)+1)
} else{
map.set(v,1)
}
})
let final = s2.filter(val=>{
if(map.has(val)){
if(map.get(val)){
map.set(val, map.get(val)-1)
return true
}
return false
}
return true
})
console.log(final)
You could count the values of the first set and return the values for a given count or if not known then all items.
var s1 = ["A", "B", "C", "D", "B"],
s2 = ["A", "B", "C", "D", "B", "A", "X", "Y"],
count = s1.reduce((m, v) => m.set(v, (m.get(v) || 0) + 1), new Map),
s3 = s2.filter(v => count.get(v) ? count.set(v, count.get(v) - 1) : !count.has(v));
console.log(...s3);
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);
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.