Join two arrays conditionally? - javascript

I wanted to join 2 arrays of the same length. However I want to join each element of with it's counterpart and produce a new array with the combined values.
// will always be string
var array = [a, b, c, d]
// Will always be number
var array2 = [1, 2, 0, 4,]
var output = [a1, b2, c0, d4]
I then want to edit the output array removing any values of 0.
So my final output should be:
var result = [a1, b2, d4]
Any thoughts and suggestions much appreciated.

Use map and filter
var result = array.map( (s, i) => [s , array2[i]] ) //combine values
.filter( s => s[1] != 0 ) //filter out 0s
.map( s => s.join("") ); //join them
Demo
// will always be string
var array = ["a", "b", "c", "d"];
// Will always be number
var array2 = [1, 2, 0, 4, ];
var result = array.map((s, i) => [s, array2[i]]) //combine values
.filter(s => s[1] != 0) //filter out 0s
.map(s => s.join("")); //join them
console.log(result);

Check this repl: https://repl.it/#Freundschaft/MeagerNocturnalFormats
// will always be string
var array = ["a", "b", "c", "d"]
// Will always be number
var array2 = [1, 2, 0, 4,]
function joinArraysCustom (firstArray, secondArray){
if(firstArray.length !== secondArray.length){
throw new Error('Arrays must match');
}
return firstArray.map(function(value, index){
return "" + value + secondArray[index];
}).filter(value => !value.endsWith('0'))
}
console.log(joinArraysCustom (array, array2));

You may use .reduce() and .push():
var arr1 = ['a', 'b', 'c', 'd'];
var arr2 = [1, 2, 0, 4];
function createArray(s, n) {
return n.reduce((a, c, i) => (
/* combine and push if current value is not zero
* otherwise return same array
*/
c != 0 ? (a.push(c + s[i]), a) : a
), []);
}
console.log(createArray(arr1, arr2));
Useful Resources:
Array.prototype.reduce()
Array.prototype.push()
Arrow functions
Comma Operator

Related

Combine splitted 2 string into array of object react js [duplicate]

I have 2 arrays:
var a = [1, 2, 3]
var b = [a, b, c]
What I want to get as a result is:
[[1, a], [2, b], [3, c]]
It seems simple but I just can't figure out.
I want the result to be one array with each of the elements from the two arrays zipped together.
Use the map method:
var a = [1, 2, 3]
var b = ['a', 'b', 'c']
var c = a.map(function(e, i) {
return [e, b[i]];
});
console.log(c)
DEMO
Zip Arrays of same length:
Using Array.prototype.map()
const zip = (a, b) => a.map((k, i) => [k, b[i]]);
console.log(zip([1,2,3], ["a","b","c"]));
// [[1, "a"], [2, "b"], [3, "c"]]
Zip Arrays of different length:
Using Array.from()
const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);
console.log( zip([1,2,3], ["a","b","c","d"]) );
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Using Array.prototype.fill() and Array.prototype.map()
const zip = (a, b) => Array(Math.max(b.length, a.length)).fill().map((_,i) => [a[i], b[i]]);
console.log(zip([1,2,3], ["a","b","c","d"]));
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Zip Multiple (n) Arrays:
const zip = (...arr) => Array(Math.max(...arr.map(a => a.length))).fill().map((_,i) => arr.map(a => a[i]));
console.log(zip([1,2], [3,4], [5,6])); // [[1,3,5], [2,4,6]]
Zipping by leveraging generator functions
You can also use a generator function to zip().
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
/**
* Zips any number of arrays. It will always zip() the largest array returning undefined for shorter arrays.
* #param {...Array<any>} arrays
*/
function* zip(...arrays){
const maxLength = arrays.reduce((max, curIterable) => curIterable.length > max ? curIterable.length: max, 0);
for (let i = 0; i < maxLength; i++) {
yield arrays.map(array => array[i]);
}
}
// put zipped result in an array
const result = [...zip(a, b)]
// or lazy generate the values
for (const [valA, valB] of zip(a, b)) {
console.log(`${valA}: ${valB}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
The above works for any number of arrays and will zip() the longest array so undefined is returned as a value for shorter arrays.
Zipping of all Iterables
Here a function which can be used for all Iterables (e.g. Maps, Sets or your custom Iterable), not just arrays.
const a = [1, 2, 3];
const b = ["a", "b", "c"];
/**
* Zips any number of iterables. It will always zip() the largest Iterable returning undefined for shorter arrays.
* #param {...Iterable<any>} iterables
*/
function* zip(...iterables) {
// get the iterator of for each iterables
const iters = [...iterables].map((iterable) => iterable[Symbol.iterator]());
let next = iters.map((iter) => iter.next().value);
// as long as any of the iterables returns something, yield a value (zip longest)
while(anyOf(next)) {
yield next;
next = iters.map((iter) => iter.next().value);
}
function anyOf(arr){
return arr.some(v => v !== undefined);
}
}
// put zipped result in aa array
const result = [...zip(a, new Set(b))];
// or lazy generate the values
for (const [valA, valB] of zip(a, new Set(b))) {
console.log(`${valA}: ${valB}`);
}
Obviously it would also be possible to just use [...Iterable] to transform any Iterable to an array and then use the first function.
Using the reduce method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
var c = a.reduce((acc, curr, ind) => {
acc.push([curr, b[ind]]);
return acc;
}, []);
console.log(c)
With forEach method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
const c = [];
a.forEach((el, ind) => {
c.push([el, b[ind]])
});
console.log(c)
Providing a solution with imperative programming by a simple for loop.
This performs better when doing the zip operation on huge data sets compared to the convenient array functions like map() and forEach().
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = [];
for (let i = 0; i < a.length; i++) {
result.push([a[i], b[i]]);
}
console.log(result);
And if you want a 1 line simpler solution then you can use a library like ramda which has a zip function.
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = R.zip(a, b);
console.log(result);

How to convert an array of strings into an array of objects with non index keys and dynamic values in JavaScript [duplicate]

I have two arrays: newParamArr and paramVal.
Example values in the newParamArr array: [ "Name", "Age", "Email" ].
Example values in the paramVal array: [ "Jon", 15, "jon#gmail.com" ].
I need to create a JavaScript object that places all of the items in the array in the same object. For example { [newParamArr[0]]: paramVal[0], [newParamArr[1]]: paramVal[1], ... }.
In this case, the result should be { Name: "Jon", "Age": 15, "Email": "jon#gmail.com" }.
The lengths of the two arrays are always the same, but the length of arrays can increase or decrease. That means newParamArr.length === paramVal.length will always hold.
None of the below posts could help to answer my question:
Javascript Recursion for creating a JSON object
Recursively looping through an object to build a property list
var keys = ['foo', 'bar', 'baz'];
var values = [11, 22, 33]
var result = {};
keys.forEach((key, i) => result[key] = values[i]);
console.log(result);
Alternatively, you can use Object.assign
result = Object.assign(...keys.map((k, i) => ({[k]: values[i]})))
or the object spread syntax (ES2018):
result = keys.reduce((o, k, i) => ({...o, [k]: values[i]}), {})
or Object.fromEntries (ES2019):
Object.fromEntries(keys.map((_, i) => [keys[i], values[i]]))
In case you're using lodash, there's _.zipObject exactly for this type of thing.
Using ECMAScript2015:
const obj = newParamArr.reduce((obj, value, index) => {
obj[value] = paramArr[index];
return obj;
}, {});
(EDIT) Previously misunderstood the OP to want an array:
const arr = newParamArr.map((value, index) => ({[value]: paramArr[index]}))
I needed this in a few places so I made this function...
function zip(arr1,arr2,out={}){
arr1.map( (val,idx)=>{ out[val] = arr2[idx]; } );
return out;
}
console.log( zip( ["a","b","c"], [1,2,3] ) );
> {'a': 1, 'b': 2, 'c': 3}
I know that the question is already a year old, but here is a one-line solution:
Object.assign( ...newParamArr.map( (v, i) => ( {[v]: paramVal[i]} ) ) );
The following worked for me.
//test arrays
var newParamArr = [1, 2, 3, 4, 5];
var paramVal = ["one", "two", "three", "four", "five"];
//create an empty object to ensure it's the right type.
var obj = {};
//loop through the arrays using the first one's length since they're the same length
for(var i = 0; i < newParamArr.length; i++)
{
//set the keys and values
//avoid dot notation for the key in this case
//use square brackets to set the key to the value of the array element
obj[newParamArr[i]] = paramVal[i];
}
console.log(obj);
You can use Object.assign.apply() to merge an array of {key:value} pairs into the object you want to create:
Object.assign.apply({}, keys.map( (v, i) => ( {[v]: values[i]} ) ) )
A runnable snippet:
var keys = ['foo', 'bar', 'baz'];
var values = [11, 22, 33]
var result = Object.assign.apply({}, keys.map( (v, i) => ( {[v]: values[i]} ) ) );
console.log(result); //returns {"foo": 11, "bar": 22, "baz": 33}
See the documentation for more
Object.fromEntries takes an array of key, value tuples and return the zipped result as object, you can then use it as follow:
const keys = ["a","b","c"];
const values = [1,2,3];
Object.fromEntries(keys.map((key, index)=> [key, values[index]])); // {a: 1, b: 2, c: 3}
Use a loop:
var result = {};
for (var i = 0; i < newParamArr.length; i++) {
result[newParamArr[i]] = paramArr[i];
}
This one works for me.
var keys = ['foo', 'bar', 'baz'];
var values = [11, 22, 33]
var result = {};
keys.forEach(function(key, i){result[key] = values[i]});
console.log(result);

How to check if array elements match some pattern (eg:XXXXYY)?

For example,I have array:
[1,2,3,2,2,2,1,2,3]
, which matches the pattern XXXXYY because it has (at least) four '2' and two '1', but my question is, how to I check if the array matches such pattern? I tried:
const arr=[1,2,3,2,2,2,1,3,2];
const pattern=[4,2];
let m=new Map();
for(const num of arr){
if(!m[num]){
m[num]=0;
}
m[num]++;
}
let i=0;
let isMatch=true;
for(const key in m){
if(m[key]<pattern[i]){
isMatch=false;
}
i++;
}
console.log(isMatch);
But isMatch is false. Is there any simpler method to do this?
You could count the values and then take the sorted counts and check against the sorted pattern.
var DESC = (a, b) => b - a,
array = [1, 2, 3, 2, 2, 2, 1, 3, 2],
pattern = [4, 2],
count = Array
.from(array.reduce((m, v) => m.set(v, (m.get(v) || 0) + 1), new Map).values())
.sort(DESC),
check = pattern
.sort(DESC)
.every((c, i) => count[i] >= c);
console.log(check);
console.log(count);

How to merge two arrays in JavaScript and keep their order

I had an whiteboard task that stumped me in the interview, however I have written a solution and wondered if anyone has improvements on it as I'm iterating which the interviewer said not to. The two arrays must be merged with the order being array1[0], array2[0], array1[1], array2[1]... (see expectedResult) etc
const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]]
const expectedResult = [1, "a", 12, "b", 5, "c", "d", "e"]
function mergeArrays(first, second) {
let returnArray = []
first.forEach((value, key) => {
returnArray.push(value)
if (second[key]) returnArray.push(second[key])
if (!first[key + 1] && second[key + 1]) {
returnArray.push(
...second.slice(key + 1, second.length)
)
}
})
return returnArray
}
const result = mergeArrays(options[0], options[1])
console.log(result.toString() === expectedResult.toString(), result)
With reduce (as an alternative to the classical for/while loop control structures)
const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]];
const expectedResult = [1, "a", 12, "b", 5, "c", "d", "e"]
// a is the accumulator
// cV, cI are resp. current value and current index
result = options[0].reduce(function (a, cV, cI) {
return a.concat([cV,options[1][cI]]);
},[]);
result = result.concat(options[1].splice(options[0].length));
console.log(result.toString() === expectedResult.toString(), result)
At each step two elements are added to the accumulator array a using concat.
I go the classic way, with a while loop, because it minimize the checks inside of the loop and appends without another check just the rest of one of the arrays.
function mergeArrays(first, second) {
var min = Math.min(first.length, second.length),
i = 0,
result = [];
while (i < min) {
result.push(first[i], second[i]);
++i;
}
return result.concat(first.slice(min), second.slice(min));
}
const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]];
console.log(mergeArrays(...options));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Instead of using value in if conditions , check for length of array.
Problems I see in code are at conditions
if (second[key]) returnArray.push(second[key])
// will not run if second[key] is 0,null,undefined.
if (!first[key + 1] && second[key + 1])
// will produce unwanted result if value reference is 0,null,undefined.
so instead, check for length would produce better result
So the condition
if (second[key]) returnArray.push(second[key])
can be changed into
if( second.length > key) returnArray.push(second[key])
You can use a recursive zipping function, using spread to feed an array of two into it as its parameters:
var z = (a, b) => a.length ? [a[0], ...z(b, a.slice(1))] : b;
var options =
[
[1, 12, 5],
["a", "b", "c", "d", "e"]
];
var expectedResult = z(...options);
console.log(JSON.stringify(expectedResult));
or for any number of array inputs:
var z = (a = [], ...b) =>
b.length ? a.length ? [a[0], ...z(...b, a.slice(1))] : z(...b) : a;
var options =
[
[1, 2],
'♦♡♣♤♥♢',
['A', 'B', 'C'],
['😊', '😔', '😠'],
[null, NaN, undefined]
];
var expectedResult = z(...options);
var stringify = (o) => JSON.stringify(o, (k, v) => v === undefined ? '__undefined__' : v !== v ? '__NaN__' : v).replace(/"__undefined__"/g, 'undefined').replace(/"__NaN__"/g, 'NaN');
console.log(stringify(expectedResult));

Getting elements of an array depending on corresponding values of another - Lodash

I have two JavaScript arrays:
var array1 = ['a','b','c','d'];
var array2 = [ 1, 0, 0, 1 ];
I want another array getting elements from array1 where the corresponding elements of array 2 in the same position match a condition. Both arrays must have the same elements.
For example:
I want elements of array1 where the corresponding elements of array2 are 0
Result = ['b','c']
Another example:
I want elements of array1 where corresponding elements of array2 are 1
Result = ['a','d']
I'm looking for a function on Lodash or Underscore Js Libraries to do this. I can implement it using vanilla javascript, but I'm curious to know if this can be done with these Libraries.
It's just the same as in plain Javascript.
filtered0 = array1.filter((_, i) => array2[i] === 0);
filtered1 = array1.filter((_, i) => array2[i] === 1);
var array1 = ['a','b','c','d'],
array2 = [ 1, 0, 0, 1 ];
console.log(_.filter(array1, (a, i) => array2[i] === 0));
console.log(_.filter(array1, (a, i) => array2[i] === 1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
This can be done elegantly by adding the following method to lodash:
_.mixin({'iter': xs => (w => () => w.next().value)(_(xs))})
Basically, it returns a function that iterates an array, that is, each invocation returns the next array element. With iter, your problem is easy:
var array1 = ['a','b','c','d'];
var array2 = [ 1, 0, 0, 1 ];
_.mixin({'iter': xs => (w => () => w.next().value)(_(xs))});
// positives
pos = _.filter(array1, _.iter(array2))
console.log(pos)
// negatives
neg = _.reject(array1, _.iter(array2))
console.log(neg)
// both
group = _.groupBy(array1, _.iter(array2))
console.log(group)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
You can zip(), filter(), and map(), like this:
_.chain()
.zip(array1, array2)
.filter(_.property(1))
.map(0)
.value();
You can get the zero values by negating the filter predicate, like this:
_.chain()
.zip(array1, array2)
.filter(_.negate(_.property(1)))
.map(0)
.value();
You can create custom function and use filter() but both arrays must be of same length.
var array1 = ['a', 'b', 'c', 'd'];
var array2 = [1, 0, 0, 1];
function filterBy(el) {
return array1.filter(function(e, i) {
return array2[i] == el;
})
}
console.log(filterBy(0))
console.log(filterBy(1))

Categories

Resources