I need loop thought two array and return another array with different values.
Example of two arrays:
let arr1 = ['one' , 'two' , 'three'];
let arr2 = ['four' , 'one' , 'two'];
What do I need?
Loop thought both array and return the same value, I expect new array like:
let res = [
{ name : 'one' , isSame: true },
{ name : 'two' , isSame: true },
{ name : 'three' },
{ name : 'four' }
];
I am removed the duplicate items and add isSame value to true on duplicated values.
One and two are duplicated ( twice ).
What I have tried
let arr3 = arr1.map((item, i) =>
Object.assign({}, item, arr2[i])
);
But I got a splitted array and it's removed duplicated
Reduce to an intermediate object and then map that object's entries:
const arr1 = ['one' , 'two' , 'three'];
const arr2 = ['four' , 'one' , 'two'];
const result = Object.entries([...arr1, ...arr2].reduce(
(a, v) => ({ ...a, [v]: v in a }),
{}
)).map(([name, isSame]) => ({ name, isSame }));
console.log(result);
The spreading behavior in the reduce() callback increases time complexity in favor of being more terse, but can easily be avoided, making this solution O(n):
const arr1 = ['one' , 'two' , 'three'];
const arr2 = ['four' , 'one' , 'two'];
const result = Object.entries([...arr1, ...arr2].reduce(
(a, v) => {
a[v] = v in a;
return a;
},
{}
)).map(([name, isSame]) => ({ name, isSame }));
console.log(result);
I would suggest you to use reduce() to do it
let arr1 = ['one' , 'two' , 'three'];
let arr2 = ['four' , 'one' , 'two'];
let arr3 = arr1.concat(arr2)
let result = arr3.reduce((a,c) =>{
let obj = a.find(i => i.name == c)
if(obj){
obj['isSame'] = true
}else{
a.push({'name':c})
}
return a
},[])
console.log(result)
Update:
solution without reduce(),using set() to remove duplicate elements,and using includes() to find duplicate elements
let arr1 = ['one' , 'two' , 'three'];
let arr2 = ['four' , 'one' , 'two'];
let arr3 = [...new Set(arr1.concat(arr2))]
let result = arr3.map(a =>{
let data = {'name':a}
if(arr1.includes(a) && arr2.includes(a)){
data["isSame"] = true
}
return data
})
console.log(result)
Update: Based on OP's comments,show with opposite result
let arr1 = ['one' , 'two' , 'three'];
let arr2 = ['four' , 'one' , 'two'];
let arr3 = [...new Set(arr1.concat(arr2))]
let result = arr3.map(a =>{
let data = {'name':a}
if(!arr1.includes(a) || !arr2.includes(a)){
data["isSame"] = true
}
return data
})
console.log(result)
Since you don't want reduce, you can loop through each item, and check the next few values.
This is natively faster with less function calls, just two for loops.
let arr1 = ['one', 'two', 'three'];
let arr2 = ['four', 'one', 'two'];
console.log(merge(arr1, arr2));
function merge(a, b) {
const merged = a.concat(b); // combine arrays
const result = [];
let stop = merged.length; // create a variable for when to stop
for(let i = 0; i < stop; i++) {
const current = merged[i];
let same = false;
// look through the rest of the array for indexes
for(let t = i + 1; t < stop; t++) {
if(current === merged[t]) {
same = true;
merged.splice(t, 1); // remove duplicate elements from the array so we don't come across it again
stop--; // we've removed an element from the array, so we have to stop 1 earlier
// we don't break this loop because there may be more than 2 occurences
}
}
const out = { name: current };
if(same) out.isSame = true;
result.push(out);
}
return result;
}
I have used map() function of array.
map() returns new array by performing code logic on each valid entry.
[...new Set([...arr1, ...arr2])], this will return new array with unique values.
I am assuming, that you are checking if value is in both array or not and based upon that we are returning object.
let arr1 = ['one', 'two', 'three'];
let arr2 = ['four', 'one', 'two'];
let mergedArray = [...new Set([...arr1, ...arr2])];
let result = mergedArray.map(value => {
if (arr1.includes(value) && arr2.includes(value)) {
return {
value,
isInBothArray: true
}
} else {
return {
value,
isInBothArray: false
}
}
});
console.log(result);
const arr1 = ['one' , 'two' , 'three'];
const arr2 = ['four' , 'one' , 'two'];
// returns the duplicate values in the two arrays
const findDuplicates = (arr) => {
let sorted_arr = arr.slice().sort();
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
return results;
}
let values = ([...new Set([...arr1, ...arr2])]);
let duplicates = findDuplicates(values);
let retval = [];
for(let i = 0; i < values.length; i++) {
let isSame = duplicates.includes(values[i]);
retval.push({name: values[i], isSame: isSame})
}
const arr1 = ['one', 'two', 'three'];
const arr2 = ['four', 'one', 'two'];
const result = Array.from(new Set(arr1.concat(arr2))).reduce((p, c) => {
const obj = { name: c };
if (arr1.concat(arr2).join("").split(c).length - 1 > 1) obj.isSame = true;
p.push(obj)
return p;
}, []);
console.log(result);
Related
I'm trying to create a combination of all possible variants of the arrays given below, which are pretty self-explanatory.
let arr1 = ['Small', 'Medium', 'Large', 'Extra-Large']
let arr2 = ['Black','Red','White']
let arr3 = ['Normal','Limited-Edition']
let combos = []
arr1.forEach((i) => {
arr2.forEach((j) => {
arr3.forEach((k) => {
combos.push(i + '-' + j + '-' + k)
})
})
})
console.log(combos)
This gives the output I want, however I want to create a function that takes an arbitrary array of arrays, [arr1, arr2, arr3.....arrN] and creates a nested loop of each of them, and returns a combined value of strings.
How do I go around creating such a function?
You can use something like this using reduce. I referenced this post
let arr1 = ['Small', 'Medium', 'Large', 'Extra-Large']
let arr2 = ['Black','Red','White']
let arr3 = ['Normal','Limited-Edition']
let arr4 = ['x','y','z']
let arr = [arr1,arr2,arr3,arr4]
let combined = arr.reduce((a,c)=>{
return a.flatMap(x=>c.map(y=>x.concat(y)))
},[[]]).map((z) => z.join("-"))
console.log(combined)
console.log(combined.length) //4*3*2*3 = 72
UPDATE - This one is taken directly from the top answer with a very small modification
let arr1 = ['Small', 'Medium', 'Large', 'Extra-Large']
let arr2 = ['Black','Red','White']
let arr3 = ['Normal','Limited-Edition']
let arr4 = ['x','y','z']
let arr = [arr1,arr2,arr3,arr4]
const cartesian =
(a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat()))).map(x=>x.join("-"));
console.log(cartesian(arr))
const arr1 = ['Small', 'Medium', 'Large', 'Extra-Large']
const arr2 = ['Black','Red','White']
const arr3 = ['Normal','Limited-Edition']
const arr4 = ['x','y','z']
const arr = [arr1,arr2,arr3,arr4]
const merged = [].concat.apply([], arr);
console.log(merged);
I have an array arr1 = [1,2,3,4,5]
There is another array of objects arr2 = [{'id':2, 'name':'A'},{'id':4, 'name':'B'}]
I am looking for find elements in arr1 which are not in arr2. The expected output is [1,3,5]
I tried the following but it doesn't work.
const arr = arr1.filter(i => arr2.includes(i.id));
Can you please help?
A solution with O(arr2.length) + O(arr1.length) complexity in Vanilla JS
var arr1= [1,2,3,4,5];
var arr2 = [{'id':2, 'name':'A'},{'id':4, 'name':'B'}];
var tmp = arr2.reduce(function (acc, obj) {
acc[obj['id']] = true;
return acc;
}, {});
var result = arr1.filter(function(nr) {
return !tmp.hasOwnProperty(nr);
})
arr2 is an array of objects, so arr2.includes(i.id) doesn't work because i (an item from arr1) is a number, which doesn't have an id property, and because arr2 is an array of objects.
Turn arr2's ids into a Set first, then check whether the set contains the item being iterated over:
const arr1 = [1,2,3,4,5];
const arr2 = [{'id':2, 'name':'A'},{'id':4, 'name':'B'}];
const ids = new Set(arr2.map(({ id }) => id));
const filtered = arr1.filter(num => !ids.has(num));
console.log(filtered);
You can try with Array.prototype.some():
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
const arr1 = [1,2,3,4,5]
const arr2 = [{'id':2, 'name':'A'},{'id':4, 'name':'B'}]
const arr = arr1.filter(i => !arr2.some(j => j.id == i));
console.log(arr);
We can use the filter method like below to check the condition required
var arr1 = [1, 2, 3, 4, 5]
var arr2 = [{ 'id': 2, 'name': 'A' }, { 'id': 4, 'name': 'B' }]
var ids = [];
arr2.forEach(element => {
ids.push(element['id'])
});
var result = arr1.filter(s => ids.indexOf(s) < 0)
console.log(result)
let arr1= [1,2,3,4,5];
let arr2 = [{'id':2, 'name':'A'},{'id':4, 'name':'B'}]
let arr2Ids=arr2.map(item=>item.id);
let result=arr1.filter(n => !arr2Ids.includes(n));
You can use find on arr2 instead of includes since arr2 is composed of object
const arr = arr1.filter(i => !arr2.find(e => e.id===i));
We have same two arrays to groupby theme by index.
Two arrays with same length and different value like blow.
How to groupby two array with their index by ES6 reduce or lodash?
array1 = [1,2,3,4] OR [{a:1},{b:2},{c:3},{d:4}]
array2 = [5,6,7,8] OR [{e:5},{f:6},{g:7},{h:8}]
finalArray = [[1,5],[2,6],[3,7],[4,8]]
I'm trying with different ways like group by with reduce in es6 or lodash concat but i can't find best solution for my problems.
Try this:
let array1 = [1, 2, 3, 4];
let array2 = [5, 6, 7, 8];
let res = array1.map((value, index) => {
return [value, array2[index]]
})
console.log(res);
If it is array of objects
let array1 = [{a:1},{b:2},{c:3},{d:4}];
let array2 = [{e:5},{f:6},{g:7},{h:8}];
let res = array1.map((value, index) => {
return [Object.values(value)[0],Object.values(array2[index])[0]]
})
console.log(res)
Use lodashes zip function
// _ is lodash
const array1 = [1,2,3,4]
const array2 = [5,6,7,8]
console.log(_.zip(array1, array2))
result
[ [ 1, 5 ], [ 2, 6 ], [ 3, 7 ], [ 4, 8 ] ]
If you are working with the array of objects. Get just the values using Object.values and grab the 0th element.
const array3 = [{a:1},{b:2},{c:3},{d:4}];
const array4 = [{e:5},{f:6},{g:7},{h:8}];
function firstval(ob){
return Object.values(ob)[0]
}
console.log(_.zip(array3.map(firstval), array4.map(firstval)))
You can also write your own zip. This is a limited version. That handles only 2 elements, doesn't accept or return generators etc.
It could easily be extended to take a spread operator and therefore any number of arguments. You don't seem to need that level of flexibility though.
function zip(a, b) {
const num = Math.min(a.length, b.length);
const result = [];
for(i = 0; i < num; i++) result.push([a[i], b[i]]);
return result;
}
Following code works under these assumptions:
all input arrays have same length
if array element is object, it has only one property
function getValue(element) {
if (typeof element === 'object') {
return Object.values(element).pop()
} else {
return element
}
}
function zipArrays(arr1, arr2) {
return arr1.reduce((acc, elm1, index) => {
const elm2 = arr2[index]
const elm = [getValue(elm1), getValue(elm2)]
acc.push(elm)
return acc
}, [])
}
// usage:
const array1 = [1,2,3,4] // OR [{a:1},{b:2},{c:3},{d:4}]
const array2 = [5,6,7,8] // OR [{e:5},{f:6},{g:7},{h:8}]
const finalArray = zipArrays(array1, array2)
I want concat following two arrays by removing duplicates without assigning to third variable:
var arr1=[{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2=[{id:3,name:'EF'},{id:2,name:'CD'}];
I want arr1 like:
[{id:1,name:'AB'},{id:2,name:'CD'},{id:3,name:'EF'}]
arr1.concat(arr2);
First merge two arrays then put array into a map with their ids. Then create array from map values.
var arr1=[{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2=[{id:3,name:'EF'},{id:2,name:'CD'}];
arr1 = arr1.concat(arr2) // merge two arrays
let foo = new Map();
for(const tag of arr1) {
foo.set(tag.id, tag);
}
let final = [...foo.values()]
console.log(final)
Can use Array reduce and findIndex to achieve what you want.
var arr1=[{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2=[{id:3,name:'EF'},{id:2,name:'CD'}];
// loop over arr2, add the elements of array2 if it doesn't exist in array1
var newArr = arr2.reduce((acc, eachArr2Elem) => {
if (arr1.findIndex((eachArr1Elem) => eachArr1Elem.id === eachArr2Elem.id && eachArr1Elem.name === eachArr2Elem.name) === -1) {
acc.push(eachArr2Elem)
}
return acc
}, [...arr1]); // initialize the new Array with the contents of array1
console.log(newArr)
using the spread operator you can flatten any amount of arrays passed to the combineAndDeDup method, i have also split out some logic methods for (hopefully) more readable code. i hope this helps.
const arr1 = [{id:1,name:'AB'}, {id:2,name:'CD'}]
const arr2 = [{id:3,name:'EF'}, {id:2,name:'CD'}]
const flatten = a => [].concat.apply([], a)
const noDuplicateProps = (a, b) => Object.keys(a).some(k => a[k] === b[k])
const combineAndDeDup = (...arrs) => {
return flatten(arrs).reduce((acc, item) => {
const uniqueItem = acc.findIndex(i => noDuplicateProps(i, item)) === -1
if (uniqueItem) return acc.concat([ item ])
return acc
}, [])
}
const deDuped = combineAndDeDup(arr1, arr2)
const megaDeDuped = combineAndDeDup(arr1, arr2, arr1, arr1, arr2, arr1)
console.log(deDuped)
console.log(megaDeDuped)
If you like clean ES6 try this:
Happy code :)
function arrayWithNoDuplicates(array, field) {
const arrayWithoutNoDuplicates = array.filter((value, index, self) =>
index === self.findIndex((t) => (
t[field] === value[field]
))
)
return arrayWithoutNoDuplicates
}
const arr1 = [{id:1,name:'AB'}, {id:2,name:'CD'}]
const arr2 = [{id:3,name:'EF'}, {id:2,name:'CD'}]
// The first param is the two merged arrays and the second the field you
// to filter by
console.log(arrayWithNoDuplicates([...arr1, ...arr2], 'id'))
By using lodash _.uniqWith(array, [comparator])
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.uniqWith(objects, _.isEqual);
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
var arr1 = [{ id: 1, name: 'AB' }, { id: 2, name: 'CD' }];
var arr2 = [{ id: 3, name: 'EF' }, { id: 3, name: 'XX' }];
arr1.forEach(element => {
arr2.forEach((el, idx) => {
if (element.id === el.id || element.name === el.name) {
delete arr2[idx]
}
});
});
let data = arr1.concat(arr2)
// or arr1 = arr1.concat(arr2)
// then your arr1 contains your unique array
data variable contains your unique array
Here is the one liner that compares by id.
let result = arr1.concat( arr2.filter( i2 => !arr1.find( i1 => i1.id == i2.id ) ) );
I have modified elements to show what happens for different objects with the same id. Swap arr1 with arr2 for which array you want to keep your preferred components. There seems to be no simple way to compare objects in JavaScript, you may use JSON.stringify but that depends on elements order. You can try it out at https://playcode.io/new/ :
var arr1=[{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2=[{id:3,name:'EF'},{id:2,name:'GH'}];
let result;
result = arr1.concat( arr2.filter( i2 => !arr1.find( i1 => i1.id == i2.id ) ) );
console.log('RESULT: ' + JSON.stringify(result));
result = arr1.concat(
arr2.filter(
i2 => !arr1.find(
i1 => {
console.log('I1: ' + JSON.stringify(i1) + ' I2: ' + JSON.stringify(i2));
return i1.id == i2.id;}
)
)
);
console.log('RESULT: ' + JSON.stringify(result));
result = arr2.concat(
arr1.filter(
i1 => !arr2.find(
i2 => {
console.log('I1: ' + JSON.stringify(i1) + ' I2: ' + JSON.stringify(i2));
return i1.id == i2.id;}
)
)
);
console.log('RESULT: ' + JSON.stringify(result));
Both lodash function unionBy and unionWith can solve your problem.
If your objects has unique key, unionBy is the most elegant way to handle it.
var arr1 = [{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2 = [{id:3,name:'EF'},{id:2,name:'CD'}];
var mergedWithoutDups = _.unionBy(arr1, arr2. 'id')
If your object has no unique key, use unionWith and isEqual instead. This will take deep comparison on all objects to remove duplicate.
var arr1 = [{id:1,name:'AB'},{id:2,name:'CD'}];
var arr2 = [{id:3,name:'EF'},{id:2,name:'CD'}];
var mergedWithoutDups = _.unionWith(arr1, arr2. _.isEqual)
I have 3 arrays in Javascript :
var arr1 = [[34.086586, -84.52345500000001], [34.080705, -84.52081499999997], [34.136911, -83.97300999999999], [34.090184, -84.51971000000003], [33.99105, -83.717806]];
var arr2 = [[34.29712, -83.86256700000001]];
var arr3 = [[33.99105, -83.717806]];
How can I check if arr2 or arr3 are inside arr1 ?
Thanks
You could iterate over the haystack and the needles and if the length of the arrays inside is equal, check every value.
function check(haystack, needles) {
return haystack.some(function (h) {
return needles.some(function (n) {
return h.length === n.length && h.every(function (a, i) {
return a === n[i];
});
});
});
}
var arr1 = [[34.086586, -84.52345500000001], [34.080705, -84.52081499999997], [34.136911, -83.97300999999999], [34.090184, -84.51971000000003], [33.99105, -83.717806]],
arr2 = [[34.29712, -83.86256700000001]],
arr3 = [[33.99105, -83.717806]];
console.log(check(arr1, arr2));
console.log(check(arr1, arr3));