Merge two arrays as if shuffling cards without iterating? - javascript

In javascript, is there an easy way to merge 2 arrays as if shuffling a deck of cards?
For example:
[ "1", "2", "3" ] +
[ "a", "b", "c" ]
=> [ "1", "a", "2", "b", "3", "c" ]

This action is typically called "zip".
Underscore.js has an implementation of it:
var a1 = [ "1", "2", "3" ];
var a2 = [ "a", "b", "c" ];
var zipped = _.zip(a1, a2);
If you want a random order, you can use shuffle:
var shuffled = _.shuffle(a1.concat(a2));

var arr1 = ["1", "2", "3"];
var arr2 = ["a", "b", "c"];
You can just loop through the arrays and create a new one. This example assumes that arr1 and arr2 are the same length.
var result = (function(a, b){
for(var i = 0, result = []; i < a.length; i++)
result.push(a[i], b[i]);
return result;
})(arr1, arr2);
// result == ["1", "a", "2", "b", "3", "c"]

You can't do it without iterating, but you can hide the iteration behind some array functions.
var a = [ "1", "2", "3" ];
var b = [ "a", "b", "c" ];
// only works if a and b have the same length
var c = a.concat(b).map(function(item, index, arr){
return index % 2 ? arr[arr.length/2 + (index+1)/2 - 1] : arr[index/2];
});
console.log(c);

You can create a closure that can be used as an array for reading (i.e. c(i) returns i-th element of result):
c = function(i){ return [a, b][i & 1][i >> 1]; };
or, probably more efficient, as
c = function(i){ return (i & 1) ? b[i >> 1] : a[i >> 1]; };
The nice thing of this approach is that you don't build all elements at once, but you will just get the element from the original arrays only if requested.
This also allows using functions instead of arrays for a and b:
c = function(i){ return (i & 1) ? b(i >> 1) : a(i >> 1); };

Related

Creating an array that comprises all possible combinations of two separate arrays' values [duplicate]

I have two arrays:
var array1 = ["A", "B", "C"];
var array2 = ["1", "2", "3"];
How can I set another array to contain every combination of the above, so that:
var combos = ["A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", "C3"];
Or if you'd like to create combinations with an arbitrary number of arrays of arbitrary sizes...(I'm sure you can do this recursively, but since this isn't a job interview, I'm instead using an iterative "odometer" for this...it increments a "number" with each digit a "base-n" digit based on the length of each array)...for example...
combineArrays([ ["A","B","C"],
["+", "-", "*", "/"],
["1","2"] ] )
...returns...
[
"A+1","A+2","A-1", "A-2",
"A*1", "A*2", "A/1", "A/2",
"B+1","B+2","B-1", "B-2",
"B*1", "B*2", "B/1", "B/2",
"C+1","C+2","C-1", "C-2",
"C*1", "C*2", "C/1", "C/2"
]
...each of these corresponding to an "odometer" value that
picks an index from each array...
[0,0,0], [0,0,1], [0,1,0], [0,1,1]
[0,2,0], [0,2,1], [0,3,0], [0,3,1]
[1,0,0], [1,0,1], [1,1,0], [1,1,1]
[1,2,0], [1,2,1], [1,3,0], [1,3,1]
[2,0,0], [2,0,1], [2,1,0], [2,1,1]
[2,2,0], [2,2,1], [2,3,0], [2,3,1]
The "odometer" method allows you to easily generate
the type of output you want, not just the concatenated strings
like we have here. Besides that, by avoiding recursion
we avoid the possibility of -- dare I say it? -- a stack overflow...
function combineArrays( array_of_arrays ){
// First, handle some degenerate cases...
if( ! array_of_arrays ){
// Or maybe we should toss an exception...?
return [];
}
if( ! Array.isArray( array_of_arrays ) ){
// Or maybe we should toss an exception...?
return [];
}
if( array_of_arrays.length == 0 ){
return [];
}
for( let i = 0 ; i < array_of_arrays.length; i++ ){
if( ! Array.isArray(array_of_arrays[i]) || array_of_arrays[i].length == 0 ){
// If any of the arrays in array_of_arrays are not arrays or zero-length, return an empty array...
return [];
}
}
// Done with degenerate cases...
// Start "odometer" with a 0 for each array in array_of_arrays.
let odometer = new Array( array_of_arrays.length );
odometer.fill( 0 );
let output = [];
let newCombination = formCombination( odometer, array_of_arrays );
output.push( newCombination );
while ( odometer_increment( odometer, array_of_arrays ) ){
newCombination = formCombination( odometer, array_of_arrays );
output.push( newCombination );
}
return output;
}/* combineArrays() */
// Translate "odometer" to combinations from array_of_arrays
function formCombination( odometer, array_of_arrays ){
// In Imperative Programmingese (i.e., English):
// let s_output = "";
// for( let i=0; i < odometer.length; i++ ){
// s_output += "" + array_of_arrays[i][odometer[i]];
// }
// return s_output;
// In Functional Programmingese (Henny Youngman one-liner):
return odometer.reduce(
function(accumulator, odometer_value, odometer_index){
return "" + accumulator + array_of_arrays[odometer_index][odometer_value];
},
""
);
}/* formCombination() */
function odometer_increment( odometer, array_of_arrays ){
// Basically, work you way from the rightmost digit of the "odometer"...
// if you're able to increment without cycling that digit back to zero,
// you're all done, otherwise, cycle that digit to zero and go one digit to the
// left, and begin again until you're able to increment a digit
// without cycling it...simple, huh...?
for( let i_odometer_digit = odometer.length-1; i_odometer_digit >=0; i_odometer_digit-- ){
let maxee = array_of_arrays[i_odometer_digit].length - 1;
if( odometer[i_odometer_digit] + 1 <= maxee ){
// increment, and you're done...
odometer[i_odometer_digit]++;
return true;
}
else{
if( i_odometer_digit - 1 < 0 ){
// No more digits left to increment, end of the line...
return false;
}
else{
// Can't increment this digit, cycle it to zero and continue
// the loop to go over to the next digit...
odometer[i_odometer_digit]=0;
continue;
}
}
}/* for( let odometer_digit = odometer.length-1; odometer_digit >=0; odometer_digit-- ) */
}/* odometer_increment() */
Just in case anyone is looking for Array.map solution
var array1=["A","B","C"];
var array2=["1","2","3","4"];
console.log(array1.flatMap(d => array2.map(v => d + v)))
Seeing a lot of for loops in all of the answers...
Here's a recursive solution I came up with that will find all combinations of N number of arrays by taking 1 element from each array:
const array1=["A","B","C"]
const array2=["1","2","3"]
const array3=["red","blue","green"]
const combine = ([head, ...[headTail, ...tailTail]]) => {
if (!headTail) return head
const combined = headTail.reduce((acc, x) => {
return acc.concat(head.map(h => `${h}${x}`))
}, [])
return combine([combined, ...tailTail])
}
console.log('With your example arrays:', combine([array1, array2]))
console.log('With N arrays:', combine([array1, array2, array3]))
//-----------UPDATE BELOW FOR COMMENT---------
// With objects
const array4=[{letter: "A"}, {letter: "B"}, {letter: "C"}]
const array5=[{number: 1}, {number: 2}, {number: 3}]
const array6=[{color: "RED"}, {color: "BLUE"}, {color: "GREEN"}]
const combineObjects = ([head, ...[headTail, ...tailTail]]) => {
if (!headTail) return head
const combined = headTail.reduce((acc, x) => {
return acc.concat(head.map(h => ({...h, ...x})))
}, [])
return combineObjects([combined, ...tailTail])
}
console.log('With arrays of objects:', combineObjects([array4, array5, array6]))
A loop of this form
combos = [] //or combos = new Array(2);
for(var i = 0; i < array1.length; i++)
{
for(var j = 0; j < array2.length; j++)
{
//you would access the element of the array as array1[i] and array2[j]
//create and array with as many elements as the number of arrays you are to combine
//add them in
//you could have as many dimensions as you need
combos.push(array1[i] + array2[j])
}
}
Assuming you're using a recent web browser with support for Array.forEach:
var combos = [];
array1.forEach(function(a1){
array2.forEach(function(a2){
combos.push(a1 + a2);
});
});
If you don't have forEach, it is an easy enough exercise to rewrite this without it. As others have proven before, there's also some performance advantages to doing without... (Though I contend that not long from now, the common JavaScript runtimes will optimize away any current advantages to doing this otherwise.)
Solution enhancement for #Nitish Narang's answer.
Use reduce in combo with flatMap to support N arrays combination.
const combo = [
["A", "B", "C"],
["1", "2", "3", "4"]
];
console.log(combo.reduce((a, b) => a.flatMap(x => b.map(y => x + y)), ['']))
Here is functional programming ES6 solution:
var array1=["A","B","C"];
var array2=["1","2","3"];
var result = array1.reduce( (a, v) =>
[...a, ...array2.map(x=>v+x)],
[]);
/*---------OR--------------*/
var result1 = array1.reduce( (a, v, i) =>
a.concat(array2.map( w => v + w )),
[]);
/*-------------OR(without arrow function)---------------*/
var result2 = array1.reduce(function(a, v, i) {
a = a.concat(array2.map(function(w){
return v + w
}));
return a;
},[]
);
console.log(result);
console.log(result1);
console.log(result2)
Part II: After my complicated iterative "odometer" solution of July 2018, here's a simpler recursive version of combineArraysRecursively()...
function combineArraysRecursively( array_of_arrays ){
// First, handle some degenerate cases...
if( ! array_of_arrays ){
// Or maybe we should toss an exception...?
return [];
}
if( ! Array.isArray( array_of_arrays ) ){
// Or maybe we should toss an exception...?
return [];
}
if( array_of_arrays.length == 0 ){
return [];
}
for( let i = 0 ; i < array_of_arrays.length; i++ ){
if( ! Array.isArray(array_of_arrays[i]) || array_of_arrays[i].length == 0 ){
// If any of the arrays in array_of_arrays are not arrays or are zero-length array, return an empty array...
return [];
}
}
// Done with degenerate cases...
let outputs = [];
function permute(arrayOfArrays, whichArray=0, output=""){
arrayOfArrays[whichArray].forEach((array_element)=>{
if( whichArray == array_of_arrays.length - 1 ){
// Base case...
outputs.push( output + array_element );
}
else{
// Recursive case...
permute(arrayOfArrays, whichArray+1, output + array_element );
}
});/* forEach() */
}
permute(array_of_arrays);
return outputs;
}/* function combineArraysRecursively() */
const array1 = ["A","B","C"];
const array2 = ["+", "-", "*", "/"];
const array3 = ["1","2"];
console.log("combineArraysRecursively(array1, array2, array3) = ", combineArraysRecursively([array1, array2, array3]) );
Here is another take. Just one function and no recursion.
function allCombinations(arrays) {
const numberOfCombinations = arrays.reduce(
(res, array) => res * array.length,
1
)
const result = Array(numberOfCombinations)
.fill(0)
.map(() => [])
let repeatEachElement
for (let i = 0; i < arrays.length; i++) {
const array = arrays[i]
repeatEachElement = repeatEachElement ?
repeatEachElement / array.length :
numberOfCombinations / array.length
const everyElementRepeatedLength = repeatEachElement * array.length
for (let j = 0; j < numberOfCombinations; j++) {
const index = Math.floor(
(j % everyElementRepeatedLength) / repeatEachElement
)
result[j][i] = array[index]
}
}
return result
}
const result = allCombinations([
['a', 'b', 'c', 'd'],
[1, 2, 3],
[true, false],
])
console.log(result.join('\n'))
Arbitrary number of arrays, arbitrary number of elements.
Sort of using number base theory I guess - the j-th array changes to the next element every time the number of combinations of the j-1 arrays has been exhausted. Calling these arrays 'vectors' here.
let vectorsInstance = [
[1, 2],
[6, 7, 9],
[10, 11],
[1, 5, 8, 17]]
function getCombos(vectors) {
function countComb(vectors) {
let numComb = 1
for (vector of vectors) {
numComb *= vector.length
}
return numComb
}
let allComb = countComb(vectors)
let combos = []
for (let i = 0; i < allComb; i++) {
let thisCombo = []
for (j = 0; j < vectors.length; j++) {
let vector = vectors[j]
let prevComb = countComb(vectors.slice(0, j))
thisCombo.push(vector[Math.floor(i / prevComb) % vector.length])
}
combos.push(thisCombo)
}
return combos
}
console.log(getCombos(vectorsInstance))
While there's already plenty of good answers to get every combination, which is of course the original question, I'd just like to add a solution for pagination. Whenever there's permutations involved, there's the risk of extremely large numbers. Let's say, for whatever reason, we wanted to build an interface where a user could still browse through pages of practically unlimited permutations, e.g. show permutations 750-760 out of one gazillion.
We could do so using an odometer similar to the one in John's solution. Instead of only incrementing our way through the odometer, we also calculate its initial value, similar to how you'd convert for example seconds into a hh:mm:ss clock.
function getPermutations(arrays, startIndex = 0, endIndex) {
if (
!Array.isArray(arrays) ||
arrays.length === 0 ||
arrays.some(array => !Array.isArray(array))
) {
return { start: 0, end: 0, total: 0, permutations: [] };
}
const permutations = [];
const arrayCount = arrays.length;
const arrayLengths = arrays.map(a => a.length);
const maxIndex = arrayLengths.reduce(
(product, arrayLength) => product * arrayLength,
1,
);
if (typeof endIndex !== 'number' || endIndex > maxIndex) {
endIndex = maxIndex;
}
const odometer = Array.from({ length: arrayCount }).fill(0);
for (let i = startIndex; i < endIndex; i++) {
let _i = i; // _i is modified and assigned to odometer indexes
for (let odometerIndex = arrayCount - 1; odometerIndex >= 0; odometerIndex--) {
odometer[odometerIndex] = _i % arrayLengths[odometerIndex];
if (odometer[odometerIndex] > 0 && i > startIndex) {
// Higher order values in existing odometer are still valid
// if we're not hitting 0, since there's been no overflow.
// However, startIndex always needs to follow through the loop
// to assign initial odometer.
break;
}
// Prepare _i for next odometer index by truncating rightmost digit
_i = Math.floor(_i / arrayLengths[odometerIndex]);
}
permutations.push(
odometer.map(
(odometerValue, odometerIndex) => arrays[odometerIndex][odometerValue],
),
);
}
return {
start: startIndex,
end: endIndex,
total: maxIndex,
permutations,
};
}
So for the original question, we'd do
getPermutations([['A', 'B', 'C'], ['1', '2', '3']]);
-->
{
"start": 0,
"end": 9,
"total": 9,
"permutations": [
["A", "1"],
["A", "2"],
["A", "3"],
["B", "1"],
["B", "2"],
["B", "3"],
["C", "1"],
["C", "2"],
["C", "3"]
]
}
but we could also do
getPermutations([['A', 'B', 'C'], ['1', '2', '3']], 2, 5);
-->
{
"start": 2,
"end": 5,
"total": 9,
"permutations": [
["A", "3"],
["B", "1"],
["B", "2"]
]
}
And more importantly, we could do
getPermutations(
[
new Array(1000).fill(0),
new Array(1000).fill(1),
new Array(1000).fill(2),
new Array(1000).fill(3),
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
['X', 'Y', 'Z'],
['1', '2', '3', '4', '5', '6']
],
750,
760
);
-->
{
"start": 750,
"end": 760,
"total": 1800000000000000,
"permutations": [
[0, 1, 2, 3, "e", "B", "Z", "1"],
[0, 1, 2, 3, "e", "B", "Z", "2"],
[0, 1, 2, 3, "e", "B", "Z", "3"],
[0, 1, 2, 3, "e", "B", "Z", "4"],
[0, 1, 2, 3, "e", "B", "Z", "5"],
[0, 1, 2, 3, "e", "B", "Z", "6"],
[0, 1, 2, 3, "e", "C", "X", "1"],
[0, 1, 2, 3, "e", "C", "X", "2"],
[0, 1, 2, 3, "e", "C", "X", "3"],
[0, 1, 2, 3, "e", "C", "X", "4"]
]
}
without the computer hanging.
Here's a short recursive one that takes N arrays.
function permuteArrays(first, next, ...rest) {
if (rest.length) next = permuteArrays(next, ...rest);
return first.flatMap(a => next.map(b => [a, b].flat()));
}
Or with reduce (slight enhancement of Penny Liu's):
function multiply(a, b) {
return a.flatMap(c => b.map(d => [c, d].flat()));
}
[['a', 'b', 'c'], ['+', '-'], [1, 2, 3]].reduce(multiply);
Runnable example:
function permuteArrays(first, next, ...rest) {
if (rest.length) next = permuteArrays(next, ...rest);
return first.flatMap(a => next.map(b => [a, b].flat()));
}
const squish = arr => arr.join('');
console.log(
permuteArrays(['A', 'B', 'C'], ['+', '-', '×', '÷'], [1, 2]).map(squish),
permuteArrays(['a', 'b', 'c'], [1, 2, 3]).map(squish),
permuteArrays([['a', 'foo'], 'b'], [1, 2]).map(squish),
permuteArrays(['a', 'b', 'c'], [1, 2, 3], ['foo', 'bar', 'baz']).map(squish),
)
I had a similar requirement, but I needed get all combinations of the keys of an object so that I could split it into multiple objects. For example, I needed to convert the following;
{ key1: [value1, value2], key2: [value3, value4] }
into the following 4 objects
{ key1: value1, key2: value3 }
{ key1: value1, key2: value4 }
{ key1: value2, key2: value3 }
{ key1: value2, key2: value4 }
I solved this with an entry function splitToMultipleKeys and a recursive function spreadKeys;
function spreadKeys(master, objects) {
const masterKeys = Object.keys(master);
const nextKey = masterKeys.pop();
const nextValue = master[nextKey];
const newObjects = [];
for (const value of nextValue) {
for (const ob of objects) {
const newObject = Object.assign({ [nextKey]: value }, ob);
newObjects.push(newObject);
}
}
if (masterKeys.length === 0) {
return newObjects;
}
const masterClone = Object.assign({}, master);
delete masterClone[nextKey];
return spreadKeys(masterClone, newObjects);
}
export function splitToMultipleKeys(key) {
const objects = [{}];
return spreadKeys(key, objects);
}
one more:
const buildCombinations = (allGroups: string[][]) => {
const indexInArray = new Array(allGroups.length);
indexInArray.fill(0);
let arrayIndex = 0;
const resultArray: string[] = [];
while (allGroups[arrayIndex]) {
let str = "";
allGroups.forEach((g, index) => {
str += g[indexInArray[index]];
});
resultArray.push(str);
// if not last item in array already, switch index to next item in array
if (indexInArray[arrayIndex] < allGroups[arrayIndex].length - 1) {
indexInArray[arrayIndex] += 1;
} else {
// set item index for the next array
indexInArray[arrayIndex] = 0;
arrayIndex += 1;
// exclude arrays with 1 element
while (allGroups[arrayIndex] && allGroups[arrayIndex].length === 1) {
arrayIndex += 1;
}
indexInArray[arrayIndex] = 1;
}
}
return resultArray;
};
One example:
const testArrays = [["a","b"],["c"],["d","e","f"]]
const result = buildCombinations(testArrays)
// -> ["acd","bcd","ace","acf"]
My version of the solution by John D. Aynedjian, which I rewrote for my own understanding.
console.log(getPermutations([["A","B","C"],["1","2","3"]]));
function getPermutations(arrayOfArrays)
{
let permutations=[];
let remainder,permutation;
let permutationCount=1;
let placeValue=1;
let placeValues=new Array(arrayOfArrays.length);
for(let i=arrayOfArrays.length-1;i>=0;i--)
{
placeValues[i]=placeValue;
placeValue*=arrayOfArrays[i].length;
}
permutationCount=placeValue;
for(let i=0;i<permutationCount;i++)
{
remainder=i;
permutation=[];
for(let j=0;j<arrayOfArrays.length;j++)
{
permutation[j]=arrayOfArrays[j][Math.floor(remainder/placeValues[j])];
remainder=remainder%placeValues[j];
}
permutations.push(permutation.reduce((prev,curr)=>prev+curr,"")); }
return permutations;
}
First express arrays as array of arrays:
arrayOfArrays=[["A","B","C"],["a","b","c","d"],["1","2"]];
Next work out the number of permuations in the solution by multiplying the number of elements in each array by each other:
//["A","B","C"].length*["a","b","c","d"].length*["1","2"].length //24 permuations
Then give each array a place value, starting with the last:
//["1","2"] place value 1
//["a","b","c","d"] place value 2 (each one of these letters has 2 possibilities to the right i.e. 1 and 2)
//["A","B","C"] place value 8 (each one of these letters has 8 possibilities to the right i.e. a1,a2,b1,b2,c1,c2,d1,d2
placeValues=[8,2,1]
This allows each element to be represented by a single digit:
arrayOfArrays[0][2]+arrayOfArrays[1][3]+arrayOfArrays[2][0] //"Cc1"
...would be:
2*placeValues[2]+3*placesValues[1]+0*placeValues[2] //2*8+3*2+0*1=22
We actually need to do the reverse of this so convert numbers 0 to the number of permutations to an index of each array using quotients and remainders of the permutation number.
Like so:
//0 = [0,0,0], 1 = [0,0,1], 2 = [0,1,0], 3 = [0,1,1]
for(let i=0;i<permutationCount;i++)
{
remainder=i;
permutation=[];
for(let j=0;j<arrayOfArrays.length;j++)
{
permutation[j]=arrayOfArrays[j][Math.floor(remainder/placeValues[j])];
remainder=remainder%placeValues[j];
}
permutations.push(permutation.join(""));
}
The last bit turns the permutation into a string, as requested.
Make a loop like this
->
let numbers = [1,2,3,4,5];
let letters = ["A","B","C","D","E"];
let combos = [];
for(let i = 0; i < numbers.length; i++) {
combos.push(letters[i] + numbers[i]);
};
But you should make the array of “numbers” and “letters” at the same length thats it!

Find single value from multiple values in single array

I have a single array having multiple values in that as shown in code below.
tempstraindatasource
tempstraindatasource[0] = {
A = "0",
B = "1",
C = "2",
D = "3"
}
tempstraindatasource[1] = {
A = "4",
B = "5",
C = "6",
D = "7"
and so on like wise I have many data exist in single array
}
I want to do one procedure that finds the data are consist or not in single line like I want to find Species having name "A" = "0" or any value "B" = "0" or "C" = "0"! How can I do it in single line? Please some one help me to do this.
Thanks in advance and appreciate as well.
You could use Array#forEach for the array and check if any of the properties have the value, you need with Array#some, and push the index then to the result array.
var data = [{ a: 0, b: 1, c: 2, d: 3 }, { a: 4, b: 5, c: 6, d: 7 }],
indices = [];
data.forEach(function (a, i) {
Object.keys(a).some(function (k) {
return a[k] === 0;
}) && indices.push(i);
});
console.log(indices);
As stated in comments your question needs editing (or better a total rewrite) but I think what you need is this
var fruits = [{name: 'banana', cost: 5}, {name: 'apple', cost:2}];
var filteredArray = fruits.map(function(fruit, index){
fruit.index = index;
return fruit;
}).filter(function(fruit){
return fruit.name === 'banana';
});
document.write(JSON.stringify(filteredArray));

Pull array values associated with bitmask

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);

Match Json keys and replace with values in array

So given a simple json object
[
{"a": 1},
{"b": 2},
{"c": 3},
{"d": 4}
]
and an array like this
var arr = ["A", "B", "C"];
I want to write the most efficient function to match the lower case keys with their upper case counter parts and replace them with the uppercase letters, I started by turning the array into a object so I wont have to iterate over and over again, but Im stuck. Can someone please show me how they would handle this in the most efficient way?
Without further information on your amount of keys/possible keys, trying to make a generic solution would be like this:
var arr = [
{"a": 1},
{"b": 2},
{"c": 3},
{"d": 4}
]
var match = ["A", "B", "C"];
var objMatch = {}
for(var i=0;i<match.length;i++) objMatch[match[i].toLowerCase()] = match[i] // pass it to an object for efficient matching
for(var i=0;i<arr.length;i++){
for(var key in arr[i]){ // check if we need to replace the key
if(objMatch.hasOwnProperty(key)){
var temp = arr[i][key] // keep old value
delete arr[i][key] // delete key
arr[i][objMatch[key]] = temp // set new key with same old value
}
}
}
console.log(arr)
From what i understand from your question
var arrayOne = [
{"a": 1},
{"b": 2},
{"c": 3},
{"d": 4}
];
var arrayTwo = ["A", "B", "C"];
var tempArray = {};
$.each(arrayOne, function(key,value){
for(arrayOneKey in value){
$.each(arrayTwo, function(index,vl) {
if(vl.toLowerCase() == arrayOneKey.toLowerCase()){
tempArray[vl]=key+1;
}
});
}
});
console.log(tempArray);
var a=[
{"a": 1},
{"b": 2},
{"c": 3},
{"d": 4}
];
var arr = ["A", "B", "C"];
Define a method in Object's prototype chain to rename Object keys:
Object.prototype.changeKey = function (oName, nName) {
if (oName == nName) {
return this;
}
if (this.hasOwnProperty(oName)) {
this[nName] = this[oName];
delete this[oName];
}
return this;
};
Then find the key which matches the elements of array, then change it:
for(var i=0;i<arr.length;i++){
for(key in a[i]){
if(key === arr[i].toLowerCase()){a[i].changeKey (key,arr[i])}
}
}
Here is a fiddle
Don't make things complicated. Use map and return a new array:
function transform(arr, keys) {
return arr.map(function(el) {
var obj = {};
var key = Object.keys(el)[0];
var uc = key.toUpperCase();
obj[keys.indexOf(uc) > -1 ? uc : key] = el[key];
return obj;
});
}
transform(input, arr);
DEMO
You could use an helper object and loop throu all items and all keys.
var arr0 = [{ "a": 1 }, { "b": 2 }, { "c": 3 }, { "d": 4 }],
arr1 = ["A", "B", "C"],
obj = Object.create(null);
arr1.forEach(function (a) {
obj[a.toUpperCase()] = a;
});
arr0.forEach(function (a) {
Object.keys(a).forEach(function (k) {
var v = a[k];
if (k.toUpperCase() in obj) {
delete a[k];
a[obj[k.toUpperCase()]] = v;
}
});
});
document.write('<pre>' + JSON.stringify(arr0, 0, 4) + '</pre>');

Return value of each key in object in a for loop

I have an object and an array:
m = { "1": ["2", "3"], "6": ["4", "5"] };
var p = ["1", "6"];
I have a for loop:
for (var i = 0; i < p.length; i++) {
// Return an array that is the value of a key in m, for each key specified in p
var array = m[p[i]];
// do stuff with array
}
Any reason why the above does not work? array is still undefined after the for loop runs.
Also I think p should be [1,6] as well? Since you're using it to reference the keys in the object m.
The error happens because you have this declaration:
var p = ["1","2"];
But the m properties are:
m = {
"1": [2,3],
"6": [4,5]
}
So in p[1] makes your program read m["2"] but it doesn't have a "2" property.
Use this code instead:
var p = ["1","6"];
Your declaration of m = { "1": ["2", "3"], "6", ["4", "5"] }; gives syntax error for me. I assume you mean m = { "1": ["2", "3"], "6": ["4", "5"] };.
p.length is 2, so you have 2 iterations of the loop. In first iteration values of your expressions are:
i = 0
p[i] = "1"
m[p[i]] = m["1"] = ["2", "3"]
In second loop:
i = 1
p[i] = "2"
m[p[i]] = m["2"] (undefined)
You have only m["1"] and m["6"], no m["2"]. That's why array is undefined in the last iteration. So it remains undefined after the loop.
You may correct m declaration as following:
m = { "1": ["2", "3"], "2": ["4", "5"] };
Now you will get array = ["4", "5"] after the loop.
I can advise you not to store integers in strings. Use 2 instead of "2". Otherwise it can cause errors in the future. For example, 2 + 2 = 4 and "2" + "2" = "22". If you have "2" from some other code, use parseInt to convert it to a normal number.
Also, you don't have to create p variable with list of keys. You can simply use for..in loop to iterate through keys of your object:
m = { 1: [2, 3], 2: [4, 5] };
for(i in m) {
var array = m[i];
//do stuff
}
Keep in mind that for..in doesn't guarantee to preserve the order of keys. However, all existing implementations of for..in do preserve the order.

Categories