Flatten An array element wise in JavaScript - javascript

I have two Arrays which look like this:
array1: [["abc","def","ghi"],["jkl","mno","pqr"]],
array2: [[1,2,3,4,5],[6,7,8,9,10]]
I want to operate a Flattening operation which gives me result like this: Flatten(array1,array2):
result: [["abc","def","ghi",1,2,3,4,5],["jkl","mno","pqr",6,7,8,9,10]]
Any suggestions on the same?
Edit 1: Both the Arrays always have the same length.

You can use map() on one of them and concat() it with corresponding element of other array
Note: I am considering length of both the arrays will be equal
const arr1 = [["abc","def","ghi"],["jkl","mno","pqr"]];
const arr2 = [[1,2,3,4,5],[6,7,8,9,10]];
const flattern = (a1, a2) => a1.map((x, i) => x.concat(a2[i]))
console.log(flattern(arr1, arr2))
If lengths of arrays are not same then you will have to first find the larger array and then map over it.
const arr1 = [["abc","def","ghi"],["jkl","mno","pqr"], ['a','b','c']];
const arr2 = [[1,2,3,4,5],[6,7,8,9,10]];
const flattern = (a1, a2) =>{
if(a1.length === a2.length){
return a1.map((x, i) => x.concat(a2[i]))
}
else if(a1.length > a2.length){
return a1.map((x, i) => x.concat(a2[i] || []))
}
else{
return a2.map((x, i) => x.concat(a1[i] || []))
}
}
console.log(flattern(arr1, arr2))

Since the length of the array is same, you could use map() over one array and concat the other.
const array1 = [["abc","def","ghi"],["jkl","mno","pqr"]];
const array2 = [[1,2,3,4,5],[6,7,8,9,10]];
let result = array1.map((a, i) => a.concat(array2[i]));
console.log(result);

You can use [...].flat(), see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

Related

How to match duplicate values in nested arrays in JS

I have an array which contains nested arrays that are dynamically created, it looks like this:
[['1', '2'],['1','3', '4'],['1', '3']]
I am trying to implement AND logic by getting only duplicate values from these arrays. My expected output here would be ['1'] since all nested arrays must contain the same value.
// [['1', '2'],['1','3', '4'],['1', '3']]
const arrays = [...new Set(response)].filter(newSet => newSet.length > 0);
const builder = []; // array of all the id's no longer needed
// [[],[],[]]
arrays.forEach(arr => {
// []
arr.forEach(value => {
// [[], [], []]
const found = arrays.filter(a => a.find(v => v === value));
if (found.length === 0)
builder.push(value);
});
});
console.log(builder); // empty []
This gives me an empty array because of the filter(). How could I return an array of values that all (3 in this case but could be more) arrays contain?
Expected output with the above input would be ["1"]. Any help appreciated.
from what I understand you need the common elements from all array
let response1 = [['1', '2'],['1','3', '4'],['1', '3']]
let response2 = [['1', '2', '3'],['1','3', '4'],['1', '3']]
const getCommon = res => [...new Set(res.flat())].filter(a => res.every(c => c.includes(a)));
console.log(getCommon(response1))
console.log(getCommon(response2))
UPDATE
Apparently the set transformation is unnecessary since anyway it has to give the elements common to every array so filtering from res[0] should do
let response1 = [['1', '2'],['1','3', '4'],['1', '3']]
let response2 = [['1', '2', '3'],['1','3', '4'],['1', '3']]
const getCommon = res => res[0].filter(a => res.every(c => c.includes(a)));
console.log(getCommon(response1))
console.log(getCommon(response2))
You can make a count object that has the frequency of each number in it, and just check if the frequency of a number is equal to the length of the original array.
const getIntersectVals = (arrayOfVals)=>{
const freqs = {};
for(let arr of arrayOfVals){
for(let val of arr){
if(freqs[val]) freqs[val]++;
else freqs[val] = 1;
}
}
const uniqueVals = Object.keys(freqs);
const correctVals = uniqueVals.filter(elem=>{
return freqs[elem] === arrayOfVals.length;
})
return correctVals;
}
const arrayOfVals = [['1', '2'],['1','3', '4'],['1', '3']];
console.log(getIntersectVals(arrayOfVals))
Lodash intesection if you don't mind
const arrayOfVals = [['1', '2'],['1','3', '4'],['1', '3']];
const result = _.intersection(...arrayOfVals);
console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>

How to simply find matching values in [[], [], []] arrays in javascript

new to javascript. i have these two arrays
var array1 = [['1'],['2']];
var array2 = [['2'],['3'],['4']];
how can i find the matching values?
tried below but returns empty array probably because it's for normal array structure ['', '', '']
var matchingValue = array1.filter(value => array2.includes(value));
Logger.log(matchingValue);
Matching value should be ['2']
You can simply use .flat() to flatten the arrays so you only deal with the values like so :-
var array1 = [['1'],['2']];
var array2 = [['2'],['3'],['4']];
var matchingValue = array1.flat().filter((value) => array2.flat().includes(value) )
console.log(matchingValue);
First, let's have a function that tells if two arrays are equal:
let equal = (a, b) => a.length === b.length && a.every((_, i) => a[i] === b[i])
Then, use this function to find an intersection of two arrays:
var array1 = [['1'],['2']];
var array2 = [['2'],['3'],['4']];
let equal = (a, b) => a.length === b.length && a.every((_, i) => a[i] === b[i])
result = array1.filter(x => array2.some(y => equal(x, y)))
console.log(result)
In a more generic way, you can write intersectBy that would compute an intersection using a predicate callback:
let intersectBy = (a, b, predicate) =>
a.filter(x => b.some(y => predicate(x, y)))
Array.includes compares by identity, so it works with primitives and not with Array and Objects.
This is a solution that compares the first element of the internal arrays:
var matchingValue = array1.filter(value1 => {
return array2.map(value2 => value2[0]).includes(value1[0]);
});
Array.map is used to convert an Array of Arrays in Array of strings, then Array.includes is used to match the first element of first Array.
This works only with the current structure (arrays of one element arrays).
const array1 = [['1'],['2']];
const array2 = [['2'],['3'],['4']];
const array1Flat = [].concat(...array1);
const array2Flat = [].concat(...array2);
const matchingValue = array1Flat.filter((value) => array2Flat.includes(value));
console.log(matchingValue);
You don't need to use .flat() you can simply use concat and spread to flatten the array.

Filter by index of nested array in javascript

I have an array in javascript which contains a number of nested arrays
let data = [
["Apple","Fruit","Red"],
["Pear","Fruit","Green"],
["Orange","Fruit","Orange"],
["Carrot","Vegetable","Orange"],
["Pea","Vegetable","Green"],
["Pumpkin","Vegetable","Orange"]
]
From this array, I wish to create two new arrays. Arr1 is the unique food types (index2) and Arr2is the unique colors (Index 3).
My new arrays should be:
Arr1 = ["Fruit","Vegetable"]
Arr2 = ["Red","Green","Orange"]
I have managed to achieve this by using for each, where I've pushed every second object to an array. I then filter this new array for unique values. This is the code I'm using to do this:
var Foods = []
var Colors = []
for (var key in data) {
Foods.push(data[key][1]);
}
for (var key in data) {
Colors.push(data[key][2]);
}
let Arr1 = [...new Set(Foods)]
let Arr2 = [...new Set(Colors)]
console.log(Arr1)
console.log(Arr2)
Although this works well, as a javascript beginner, I thought there may be a more elegant way to achieve.
For example is it not possible to filter all the unique values of data with an index of [2]?
Your code is fine as it is, the only improvement would be to replace loops with map:
let foods = [...new Set(data.map(d => d[1]))]
let colors = [...new Set(data.map(d => d[2]))]
There's absolutely no need to overcomplicate matters with reduce, destructuring and so on.
If you want it to look slightly more elegant, you can define two utility functions
const item = i => a => a[i]
const uniq = a => [...new Set(a)]
and then
let foods = uniq(data.map(item(1)))
let colors = uniq(data.map(item(2)))
Another option:
const uniq = a => [...new Set(a)]
const zip = (...args) => args[0].map((_, i) => args.map(a => a[i]))
let [_, foods, colors] = zip(...data).map(uniq)
Reduce the array to two Sets, and then destructure the Sets, and spread each into the respective array:
const data = [["Apple","Fruit","Red"],["Pear","Fruit","Green"],["Orange","Fruit","Orange"],["Carrot","Vegetable","Orange"],["Pea","Vegetable","Green"],["Pumpkin","Vegetable","Orange"]]
const [s1, s2] = data.reduce((acc, arr) => {
acc.forEach((s, i) => s.add(arr[i + 1]))
return acc
}, [new Set(), new Set()])
const Arr1 = [...s1]
const Arr2 = [...s2]
console.log({ Arr1, Arr2 })
You could take a single loop and get the unique values for all items of the nested arrays.
const
getUnique = array => array
.reduce((r, a) => a.map((v, i) => (r[i] || new Set).add(v)), [])
.map(s => [...s]),
data = [["Apple", "Fruit", "Red"], ["Pear", "Fruit", "Green"], ["Orange", "Fruit", "Orange"], ["Carrot", "Vegetable", "Orange"], ["Pea", "Vegetable", "Green"], ["Pumpkin", "Vegetable", "Orange"]],
[, types, colors] = getUnique(data);
console.log(types);
console.log(colors);
Create an object with foods and colors as keys and loop through inserting the appropriate element index each iteration
let data = [
["Apple","Fruit","Red"],
["Pear","Fruit","Green"],
["Orange","Fruit","Orange"],
["Carrot","Vegetable","Orange"],
["Pea","Vegetable","Green"],
["Pumpkin","Vegetable","Orange"]
]
const uniques = {
foods:new Set(),
colors: new Set()
}
data.forEach(a => uniques.foods.add(a[1]) && uniques.colors.add(a[2]) )
// just for demo logs
Object.entries(uniques).forEach(([k,set])=> console.log(k,':', ...set))

filtering 2 arrays for unique elements

I write a function that receives 2 arrays and returns an array that has elements that exist in both arrays.
For example, if I pass [6,7,8,9] and [1,8,2,6], it should return [6,8].
My aim is not to use loops here.
I use this code:
const uniqueElements= (arr1, arr2) => {
return arr1.filter(it1=> arr2.filter((it2) => it2===it1).length>0)
}
However, if there are duplicate elements in arrays (e.g. [6,7,8,9,6] and [1,8,2,6,6]), it returns [6, 8, 6].
How should I mend my code so that it would return only unique elements without duplicates? Is it possible without using loops?
If you just want to get unique value which appears on both of the array, you just first change both of the array's to Set, loop through one Set and check if it's present on other or not, if it present return true from filter else return false,
const uniqueElements= (arr1, arr2) => {
let set1 = new Set(arr1)
let set2 = new Set(arr2)
return [...set1].filter(it1=> set2.has(it1))
}
console.log(uniqueElements([6,7,8,9],[1,8,2,6]))
console.log(uniqueElements([6,7,8,9,6],[1,8,2,6,6]))
Ref to read about Set
Set MDN
For your scenario use this -
constant uniqueElements= (arr1, arr2) => {
return Array.from(new Set(arr1.filter(it1=> arr2.filter((it2) => it2===it1).length>0)))
}
Hope this helps
Solution using Set from https://2ality.com/2015/01/es6-set-operations.html:
const uniqueElements = (arr1, arr2) => {
const a = new Set(arr1);
const b = new Set(arr2);
const intersection = new Set(
[...a].filter(x => b.has(x)));
return Array.from(intersection);
}
Simply you can just use Array#some() method to write the condition inside your Array#filter() method's callback:
const uniqueElements = (arr1, arr2) => {
let viewed = [];
return arr1.filter(it1 => {
let found = arr2.some((it2) => it2 === it1) && viewed.indexOf(it1) == -1;
viewed.push(it1);
return found;
});
}
Note:
This doesn't take duplicates, with the use of viewed array and viewed.indexOf(it1) == -1 condition.
Demo:
const uniqueElements = (arr1, arr2) => {
let viewed = [];
return arr1.filter(it1 => {
let found = arr2.some((it2) => it2 === it1) && viewed.indexOf(it1) == -1;
viewed.push(it1);
return found;
});
}
let a1 = [6,7,8,9,6];
let a2 = [1,8,2,6,6];
console.log(uniqueElements(a1, a2));

Sorting string arrays based on the number present in the element

I have to sort a string array based on the number.
Example
["1.READ","10.CREATE","3.sfg","2.dfd","12.dqwe"];
Desired Result
["1.READ","2.dfd","3.sfg","10.CREATE","12.dqwe"];
My Code
var arr = ["1.READ","10.CREATE","3.sfg","2.dfd","12.dqwe"];
var arr2 = arr.map( a => a.split('.').map( n => +n+100000 ).join('.') ).sort().map( a => a.split('.').map( n => +n-100000 ).join('.') );
console.log(arr);
console.log(arr2);
You can just split and convert the first element to Number
var arr = ["1.READ", "10.CREATE", "3.sfg", "2.dfd", "12.dqwe"];
var arr2 = arr.sort((a, b) => {
return Number(a.split(".")[0]) - Number(b.split(".")[0]);
});
console.log(arr2);
The code above will also sort the first variable. If you you only want arr2 to be sorted, you can:
var arr = ["1.READ", "10.CREATE", "3.sfg", "2.dfd", "12.dqwe"];
var arr2 = [...arr]; //Spread the array so that it will not affect the original
arr2.sort((a, b) => {
return Number(a.split(".")[0]) - Number(b.split(".")[0]);
});
console.log(arr);
console.log(arr2);
You could split and take only the first part. Then take the delta for sorting.
var array = ["1.READ", "10.CREATE", "3.sfg", "2.dfd", "12.dqwe"];
array.sort((a, b) => a.split(".")[0] - b.split(".")[0]);
console.log(array);
Here it is:
var arr = ["1.READ","10.CREATE","3.sfg","2.dfd","12.dqwe"];
arr.sort(function(a, b) {
return a.split('.')[0] - b.split('.')[0];
});
console.log(arr)
// ["1.READ", "2.dfd", "3.sfg", "10.CREATE", "12.dqwe"]
This answer base on built in array sort function, with customizable compare logic.
Check this out for more detail: Javascript Array Sort
Cheers,

Categories