Combining 2 arrays in javascript - javascript

I have 2 arrays in javascript.
var A = ['c++', 'java', 'c', 'c#', ...];
var B = [12, 3, 4, 25, ...];
Now from these 2 arrays i want to create another array like :
[['c++',12], ['java',3], ['c',4], ['c#', 25] ...];
Both A and B arrays are variable length in my case so how can i do this?

Underscore.js is good at that:
_.zip(*arrays)
Merges together the values of each of the arrays with the values at
the corresponding position. Useful when you have separate data sources
that are coordinated through matching array indexes. If you're working
with a matrix of nested arrays, zip.apply can transpose the matrix in
a similar fashion.
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

You can use this snippet if you don't to use any third party library:
var i = 0
, n = A.length
, C = [];
for (; i < n; i++) {
C.push([A[i], B[i]]);
}

function Merge(A,B){
var length = Math.min(A.length,B.length);
var result = [];
for(var i=0;i<length;i++){
result.push([ A[i], B[i] ])
}
return result;
}

I think that using a hashMap instead of 2 arrays could be a good solution for you.
In example, you could do something like the following:
var h = new Object(); // or just {}
h['c++'] = 12;
h['java'] = 3;
h['c'] = 4;
Take a look at:
http://www.mojavelinux.com/articles/javascript_hashes.html

Related

in JS, anArray = [] works but abArray.splice(0, anArray.length) and anArray.length=0 produce incorrect results in the following code:

I have several versions of a simple nested 'for loop' in the attached code. I'd like to reuse the same array for each iteration of the loop instead of creating a new array each iteration as apparently this used a lot of memory and creates excess garbage for collection.
The result of this code should be an array of arrays that holds a subset of a given larger array of arrays. The same simple code works differently depending on the method I use to clear an intermediate one-dimensional array within the outer loop to reuse it. Specifically, anArray=[] works to clear anArray, but both anArray.length=0 and anArray.splice(0, anArray.length) produce incorrect results in my code.
I know how to make this work, and I know how to code it "better". This was pulled out of functions within complex code to isolate what seems to be a bug. What I want to know is, why do the 2nd and 3rd examples not work as expected?
Disclosure: I've written lots of C and assembly doing DSP, but I'm not experienced in JavaScript. Please educate me! What knowledge am I missing that would make these results comprehensible?
If you copy the code below and paste it somewhere to run it, you'll see very clearly what happens. Please copy and run each example in isolation or they may interact and muddy the waters even more.
The code that works is this:
var sets = [
[1, 2, 3, 4, 5, 6],
[10, 20, 30, 40, 50, 60],
[100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays.
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.
for (var i = 0; i < 3; i++) {
singleSubset = []; // clear this array each outer iteration so we can use .push
for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
singleSubset.push(sets[i][di])
};
arrayOfSubsets.push(singleSubset); // push each subset array on to the output array of arrays.
}
for (j = 0; j < 3; j++) {
console.log(arrayOfSubsets[j]);
} // display result:
[2, 3, 4, 5]
[20, 30, 40, 50]
[200, 300, 400, 500]
This is as expected and correct.
Here is very similar code using .length=0 that does not work:
var sets = [
[1, 2, 3, 4, 5, 6],
[10, 20, 30, 40, 50, 60],
[100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays.
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.
for (var i = 0; i < 3; i++) {
singleSubset.length = 0; // clear this array each outer iteration so we can use .push
for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
singleSubset.push(sets[i][di])
};
arrayOfSubsets.push(singleSubset); // push each subset array on to the output array of arrays.
}
for (j = 0; j < 3; j++) {
console.log(arrayOfSubsets[j]);
} // display result:
[200, 300, 400, 500]
[200, 300, 400, 500]
[200, 300, 400, 500]
This is obviously not expected and not correct.
Here is a version that avoids using .push so the intermediate array should not need to be cleared between iterations. Nevertheless, the =[] method works, and in fact is still required or this doesn't work correctly. Try this code with each of the various methods of clearing by un-commenting as needed:
var sets = [
[1, 2, 3, 4, 5, 6],
[10, 20, 30, 40, 50, 60],
[100, 200, 300, 400, 500, 600]
] //given array of 3 arrays.
var singleSubset = []; // this simple array will hold a different subset each iteration.
var arrayOfSubsets = []; // this becomes the array of arrays that are subsets of the set arrays.
var subsetBounds = [1, 5]; // first and last+1 indices of the subsets to be extracted.
for (var i = 0; i < 3; i++) {
singleSubset = []; // works and is required or it doesn't work. But comment it out and try:
// singleSubset.length = 0; // or try:
// singleSubset.splice(0, singleSubset.length); // or for extra madness try:
// singleSubset.length = 0; singleSubset = []; // as placing .length=0 ahead of =[] produces bad output too!
for (var di = subsetBounds[0]; di < subsetBounds[1]; di++) {
singleSubset[di - subsetBounds[0]] = sets[i][di];
}
arrayOfSubsets[i] = singleSubset;
}
for (j = 0; j < 3; j++) {
console.log(arrayOfSubsets[j]);
} // display result:
[200, 300, 400, 500]
[200, 300, 400, 500]
[200, 300, 400, 500]
This is obviously not expected and not correct.
The .length=0 preceding =[] option produces this:
[]
[]
[200, 300, 400, 500]
Does any of this make sense to anyone?
I'm longing for how multi-dimensional arrays are expressed in C. So much easier to intuit!
And sure, if extracting a subset of a 2D array as a smaller 2D array can be done in one statement using better JS, I'll thank you for this too.
If you don't create a new array each time through the loop, all the elements of arrayOfSubsets will be references to the same array. When you change its length, splice it, or push new elements onto it, all of them get those changes.
So you either need to create a new array each time through the loop (this is the normal way) or make a copy when you push it onto the containing array:
arrayOfSubset.push(singleSubset.slice());
When you use singleSubset = []; you create a new array. When you use singleSubset.length = 0; or singleSubset.splice(0, singleSubset.length); you update the temp array, you've already assigned. This means that any change will be reflected on all your subsets.
In this case singleSubset.length = 0; singleSubset = []; you clear the previously assign array, and then generate a new one. This means that the 1st two subsets would be empty.
How I would do it - use Array.map() to iterate the sets and create a new array. Use slice on each subset, because slice returns a new array.
const sets = [
[1, 2, 3, 4, 5, 6],
[10, 20, 30, 40, 50, 60],
[100, 200, 300, 400, 500, 600]
]
const subsetBounds = [1, 5];
const result = sets.map(subset => subset.slice(...subsetBounds));
console.log(result);

Counting data types in an array in Javascript

I'm trying to count how many different data types are in this array, var arr. The output I am trying to return should be 2.
var arr = [12, 45, 66, 88, true, false]
var count = [];
function check_types(arr) {
for (i = 0; i <= typeof arr.length; i++) {}
return count;
}
check_types(arr)
I appreciate the feedback that helps me notice what I did wrong and so that I avoid repeating mistakes in future code. Thank you.
The output I am trying to return should be 2.
then why do you assign an array to count and not 0?
Additionally you do typeof arr.length which is "number" and it makes little sense to compare that to an index.
Now to get the number of unique types you could map the array to an array of types, then turn it into a unique Set and get its size:
return new Set(arr.map(el => typeof el)).size;
This will do the trick
function check_types(arr) {
var types = {};
arr.forEach(function(i){
if (types[typeof i] === undefined)
types[typeof i] = 1;
else
types[typeof i]++;
});
return Object.keys(types).length;
}
var arr = [12, 45, 66, 88, true, false];
console.log(check_types(arr));
Creates an object where each key represents a type in the array, and the value of each key is the number of the that type within the array.
You don't need these numbers right now, so you can just count the amount of keys in that object.
You could use an object as hash table for just setting a flag. The count the keys for used types.
var array = [12, 45, 66, 88, true, false],
types = {};
array.forEach(v => types[typeof v] = true);
console.log(types);
console.log(Object.keys(types).length);
There are couple of mistakes,
1. you need to check data types of element inside array. type of array.length is always number
2. for array , you need to loop till arr.length(i< arr.length)
var arr = [12, 45, 66, 88, true, false]
var count = [];
function check_types(arr) {
for (i = 0; i <arr.length; i++) {
let dtype = typeof arr[i]
if(!count.includes(dtype)) {
count.push(dtype)
}
}
return count.length;
}
console.log(check_types(arr))
console.log(count)

Multi-dimensional For Loop

I have three arrays and I need to create a set of rules based on these three arrays, but I'm struggling with the logic of how to write a function that will give me every possible combination of every entry in each array. So, I have, for example:
var array 1 = [1, 2];
var array 2 = [3, 4, 5];
var array 4 = [6, 7, 8, 9, 10];
And I'd wan't get back a string, object etc of all possible combinations (which I wont attempt to work out here). So for example:
var result = ["1-3-6", "2-3-6", "1,4,6"];
And so on, so far I've tried sitting down and composing a For Loop but I'm just really not sure where to start. I also looked at maps, but could not find any examples that went this deep, so I wasn't sure if a map would get the job done either.
The actual data I want to load in, the first array has 2 entries, the second have 7 and the last one had 6, so for the workings out I've done there should be 84 entries. That was based on (Array 3 * Array 2) * Array 1.
Hope that all makes sense I know it's a bit confusing. Also worth mentioning that I'm using Angular JS so an angular solution or vanilla JS solution is preferred but not essential.
What you are looking is the Cartesian product of arrays. You can use a function like this (extracted from here):
function cartesian() {
var r = [], arg = arguments, max = arg.length-1;
function helper(arr, i) {
for (var j=0, l=arg[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(arg[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
There are lot of examples, like:
JavaScript - Generating combinations from n arrays with m elements
With recursive:
Finding All Combinations of JavaScript array values
Cartesian product of multiple arrays in JavaScript
And with multiple (N) arrays:
Combine 2 arrays into 1 in all possible ways in JavaScript
Hope it helps!
Nested for loops will do
function arrComb(arr1, arr2, arr3) {
var l1 = arr1.length,
l2 = arr2.length,
l3 = arr3.length,
i, j, k, res = [];
for (i = 0; i < l1; i++) {
for (j = 0; j < l2; j++) {
for (k = 0; k < l3; k++) {
res.push(arr1[i] + '-' + arr2[j] + '-' + arr3[k]);
}
}
}
console.log(res)
}
arrComb([1, 2], [3, 4, 5], [6, 7, 8, 9, 10]);
A bit more elegant:
var array_1 = [1, 2];
var array_2 = [3, 4, 5];
var array_4 = [6, 7, 8, 9, 10];
var result = [];
for (var a1 of array_1)
{
for (var a2 of array_2)
{
for (var a3 of array_4)
{
result.push("\""+a1+"-"+a2+"-"+a3+"\"")
}
}
}
alert("["+result+"]")

Can two loops be merged into one?

I'm using the following function to add specific numbers into an array that I later want to be assigned to a variable. For this I'm using two for loops, but I feel like there is a more succinct way to do it. I tried merging the two loops in one without getting an error, but the output is not the same.
Working Example:
function fill () {
var array = [];
for (var index = 0; index < arguments.length; index++) {
for (var number = arguments[index][0]; number <= arguments[index][1]; number++)
array.push(number);
}
return array;
};
/* Use */
var keys = fill([1, 10], [32, 34]);
/* Output */
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34]
Merged Example:
function fill () {
var array = [];
for (var index = 0, number = arguments[index][0];
index < arguments.length && number <= arguments[index][1];
index++ && number++) {
array.push(number);
}
return array;
};
/* Use */
var keys = fill([1, 10], [32, 34]);
/* Output */
[1, 1]
Is it possible to actually merge the two loops into one? If not, is there a way to write the foregoing function in less code?
Your code in the first example is fine. There is no real "clean" way to remove the nested loops.
You could iterate over them with forEach, but then you'd still have nested loops, even if one of them is disguised as a function call:
function fill () {
var array = [];
Array.prototype.slice.apply(arguments) // Make an array out of arguments.
.forEach(function(arg){
for (var number = arg[0]; number <= arg[1]; number++){
array.push(number);
}
});
return array;
};
console.log(fill([1, 10], [32, 34]));
And you'd have to use Array.prototype.slice.apply to convert arguments to an actual array. (which is ugly)
So, basically, nested loops aren't necessarily "evil". Your first example is as good as it gets.
JavaScript is a functional language. For the sake of modern coding purposes a functional approach is best for the coder's benefit.
var fillArray = (...args) => args.reduce((res,arg) => res.concat(Array(...Array(arg[1]-arg[0]+1)).map((e,i) => i + arg[0])),[]),
filled = fillArray([1, 10], [32, 34]);
console.log(filled);
OK what happens here.. It's very simple. We do the job by fillArray function. fillArray function takes indefinite number of arguments. So we collect them all in an array called args by utilizing the ES6 rest operator ....
var fillArray = (...args)
Now that we have our source arrays in the args array we will apply a reduce operation to this array with an initial value of an empty array (res). What we will do is.. as per each source (arg) array we will create a new array and then we will concatenate this to the res array. Ok we receive [1,10] as source which means we need an array of length arg[1]-arg[0]+1 right. So comes
Array(...Array(arg[1]-arg[0]+1))
we could also do like Array(arg[1]-arg[0]+1).fill() same thing. We now have an array filled with "undefinite" in the needed length. Then comes map. This is really very simple as we apply to this undefinites array like
.map((e,i) => i + arg[0]))
which means each item will be the current index + offset which is the arg[0]
Then we concatenate this array to our results array and pass to the next source array. So you see it is very straight forward and maintainable.
You might not be able to escape the two loops, but that shouldn't necessarily be a goal either. The loop themselves aren't really harmful – it's only if you're iterating over the same data multiple times that you might want to reconsider your code
Consider this entirely different approach
const range = (x , y) =>
x > y
? []
: [ x, ...range (x + 1, y) ]
const concat = (xs, ys) =>
xs .concat (ys);
const flatMap = (f, xs) =>
xs .reduce ((acc, x) => concat (acc, f (x)), [])
const apply = f => xs =>
f (...xs)
const fill = (...ranges) =>
flatMap (apply (range), ranges);
console.log
(fill ( [1,10]
, [32,34]
, [40,49]
, [100,100]
)
)
So yes, #Redu is on the right track with "JavaScript is a functional language", but I think his/her answer falls short of delivering a well-composed functional answer.
The answer above shows how functions with individualized concerns can be easy to read, easy to write, and easy to combine to achieve complex computations.
In ES6, you could use the rest operator and build a new array, based on the items.
function fill(...p) {
return p.reduce((r, a) => r.concat(Array.apply(null, { length: a[1] - a[0] + 1 }).map(() => a[0]++)), []);
};
var keys = fill([1, 10], [32, 34]);
console.log(keys);
Similar to another answer, but a little more complete:
const arrays = [[1,10],[32,34],[9,12]]
const range = (a,b) => a >= b ? [] :
[...Array(b-a).keys()].map(i => i+a)
const result = arrays.reduce( (a,c) =>
a.concat( range(c[0], c[1]+1) ), [] )
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34, 9, 10, 11, 12 ]
If you prefer a more traditional range function, then:
const arrays = [[1,10],[32,34],[9,12]]
function range(a,b) {
var arr = []
for (let i = a; i < b; i++)
arr.push(i)
return arr
}
const result = arrays.reduce( function(a,c) {
return a.concat( range(c[0], c[1]+1) )
}, [] )
After almost 2 years and some great answers that were posted to this thread proposing interesting alternatives, I found a way to merge the two loops into one, but it ain't pretty!
Code:
function fill () {
var
ar = [],
imax = arguments.length,
/* The functions that calculate the bounds of j. */
jmin = i => arguments[i][0],
jmax = i => arguments[i][1] + 1;
for (
let i = 0, j = jmin(i);
i < imax && j < jmax(i);
/* If j reaches max increment i and if i is less than max set j to min. */
ar.push(j++), (j == jmax(i)) && (i++, (i < imax) && (j = jmin(i)))
);
return ar;
};
/* Use */
var keys = fill([1, 10], [32, 34], [76, 79]);
console.log.apply(console, keys);

JSON - Need to be javascript array inside of array and encode to JSON

I'm trying to produce an array that looks like this:
[
{
"values": [
[1, 0],
[2, -6.3382185140371],
[3, -5.9507873460847],
[4, -11.569146943813],
[5, -5.4767332317425],
[6, 0.50794682203014],
[7, -5.5310285460542],
[8, -5.7838296963382],
[9, -7.3249341615649],
[10, -6.7078630712489]
]
}
]
I'm doing an array in javascript that looks like this and only produce the values, but doe not place it within "values" : []:
var myArray = new Array(10);
for (i = 0; i < 10; i++) {
myArray[i] = new Array(2);
myArray[i][0] = i;
myArray[i][1] = 5;
}
var jsonEncoded = JSON.stringify(myArray);
return jsonEncoded;
I'm sure this is an easy answer, but I'm not experience enough to know. Thanks for the help in advance.
Here you go, you basically need to wrap your myArray in an object and put that object into another array.
var myArray = new Array(10);
for (i = 0; i < 10; i++) {
myArray[i] = new Array(2);
myArray[i][0] = i;
myArray[i][1] = 5;
}
var result = [{values: myArray}];
var jsonEncoded = JSON.stringify(result);
return jsonEncoded;
It should be
var jsonEncoded = JSON.stringify([{values:myArray}]);
There are several other, more verbose ways to do it, but that's it.
In this case, myArray is an array containing N elements, each one being an array of two numbers.
Enclosing {key : value} pairs in curly bracers { } means you're declaring an object. In this case, "values" is your key, and myArray is your value. No pun intended here, it's just that you picked a confusing keyname. Object notation in js does not require quoting the key.
Finally, enclosing the aforementioned object between brackets will result in an array whose only element is that object.

Categories