JavaScript loop through two arrays and get single array - javascript

I have two arrays:
var arr = [
{ id: 2, username: 'bill'},
{ id: 3, username: 'ted' }];
var b = ["ted", "bill", "john"];
how can I get one array like this:
var finalArr = [{id: 2, username: 'bill'},{id:3, username: 'ted'}. {id:0, username: 'john'}]
If user from array b exist in arr array to add id and if not id to be 0.
I tried something like this, but not working
var arr = [{
id: 2,
username: 'bill'
},
{
id: 3,
username: 'ted'
}
];
var b = ["ted", "bill", "john"];
var finalArr = [];
function userExists(username) {
var a = arr.some(item => {
if (item.username === username) {
finalArr.push({
username,
id: item.id
})
} else {
finalArr.push({
username,
id: 0
})
}
})
}
b.forEach(el => {
userExists(el)
})
console.log(finalArr)

Loop through b using map. Check if the username exists in arr using find. If yes, return the object. Else, return a new object with id: 0
var arr = [
{ id: 2, username: 'bill'},
{ id: 3, username: 'ted' }];
var b = ["ted", "bill", "john"];
const output = b.map(username => {
const found = arr.find(a => a.username === username);
return found || { username, id: 0 }
})
console.log(output)

You can use map and find to construct your new array like
var arr = [{
id: 2,
username: 'bill'
},
{
id: 3,
username: 'ted'
}
];
var b = ["ted", "bill", "john"];
const finalArr = b.map(username => {
const find = arr.find(o => o.username === username);
return find ? find : { id: 0, username }
})
console.log(finalArr)

You can do that using reduce method.
b.reduce((result, elm) => {
const userObj = arr.find((a) => a.username === elm);
if(userObj) {
result.push(userObj)
} else {
result.push({
id: 0,
username: elm
});
}
return result;
}, []);
Check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce for more details about reduce.

You can craete a dummy array for storing result and , find the existing using find. If not found create dummy object and push inside array.
var arr = [
{ id: 2, username: 'bill'},
{ id: 3, username: 'ted' }];
var b = ["ted", "bill", "john"];
myArr = [];
b.forEach(function(element) {
var el=arr.find(x => x.username === element);
if(el){
myArr.push(el);
}else{
var dummy={};
dummy.id=0;
dummy.username=element;
myArr.push(dummy);
}
});
console.log(myArr);

You could take a Set and filter by looking to the set and delete visited items. At the end concat missing items.
This solution repsects the order of the given data and adds the missing object in order of the names array.
var data = [{ id: 42, username: 'foo' }, { id: 2, username: 'bill' }, { id: 3, username: 'ted' }],
names = ["ted", "bill", "john"],
missing = new Set(names),
result = data
.filter(({ username }) => missing.delete(username))
.concat(Array.from(missing, username => ({ id: 0, username })));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Compare and update two arrays without losing mutated data

I have an array of objects contains data of persons
const oldArr = [
{
id: 1,
name: 'Alex',
},
{
id: 2,
name: 'John',
},
{
id: 3,
name: 'Jack',
}
]
then I add data to this array to each element where I end up with new key called money with value of 20 as the following
oldArr.map((el, index) => el.money = 20)
and the array becomes like this
...
{
id: 2,
name: 'John',
money: 20
},
...
Now, I have a new array with new data (new person) but missing the money I have added before. (careful person with id 2 is not there)
const newArr = [
{
id: 1,
name: 'Alex',
},
{
id: 3,
name: 'Jack',
},
{
id: 4,
name: 'Chris',
},
]
I want to update the old array with new data but also keep the mutated data, and I want the result to end up like this:
const result = [
{
id: 1,
name: 'Alex',
money: 20
},
{
id: 3,
name: 'Jack',
money: 20
},
{
id: 4,
name: 'Chris',
},
]
Thanks for the help.
Just a note: map creates a whole new array, it doesn't make sense to use it for just mutating the contents. Use forEach or just a regular for loop instead.
oldArr.forEach((el) => (el.money = 20));
The following will give you the intended result:
const result = newArr.map(
(newEl) => oldArr.find((el) => el.id === newEl.id) || newEl
);
The OR operator || returns the second argument if the first is falsey.
You can optimize this by mapping items by id instead of brute force searching the old array.
const idMap = new Map();
oldArr.forEach((el) => {
el.money = 20;
idMap.set(el.id, el);
});
const result = newArr.map((newEl) => idMap.get(newEl.id) || newEl);
Stackblitz: https://stackblitz.com/edit/js-f3sw8w?file=index.js
If I getted it clear you are just trying to iterate throw the items of array generating a new array with the property "money" added to each one.
If so the map is the best option, just assign it to a new variable and change the item before return the element like bellow.
const oldArr = [
{
id: 1,
name: "Alex"
},
{
id: 2,
name: "John"
},
{
id: 3,
name: "Jack"
}
];
const newArr = oldArr.map((el) => {
el.money = "20";
return el;
});
console.log(oldArr);
console.log(newArr);
In this way you'll be able to keep both arrays.
If wasn't this, pls let me know.
Just merge the objects:
const result = oldArr.map((person) => ({
...person,
...newArr.find((cur) => cur.id === person.id),
}));

check array of objects if specific value is unique across all the array

I have an array like this
const arr = [{ name: 'sara' }, { name: 'joe' }];
and i want to check if name is unique across the array so
const arr = [{ name: 'sara' }, { name: 'joe' }];//sara is unique //true
const arr = [{ name: 'sara' }, { name: 'sara' },{ name: 'joe' }];//sara is unique //false
i know there's array.some but it doesn't help in my situation
whats is the best way to achieve that using javascript thanks in advance
You could take a single loop and a Set for seen value.
isUnique is a function which takes a property name and returns a function for Array#every.
const
isUnique = (key, s = new Set) => o => !s.has(o[key]) && s.add(o[key]),
a = [{ name: 'sara' }, { name: 'joe' }],
b = [{ name: 'sara' }, { name: 'sara' }, { name: 'joe' }];
console.log(a.every(isUnique('name'))); // true
console.log(b.every(isUnique('name'))); // false
i have this implementation and it dose the job
const arr = [{ name: "salah" }, { name: "joe" }];
let bols = [];
arr.forEach((item1, i1) => {
arr.forEach((item2, i2) => {
if (i1 !== i2) {
bols.push(item2.name === item1.name);
}
});
});
bols.some((item) => item === true);

How to loop through array and push it into a seperate array based on some conditions using react?

i have an array named "all_items" and i want to split that to two arrays named "self" and "others".
I want to loop through each item in "all_items" array and if that item is added by current_user then push it to "self" array if not "others" array
item = {
id: 0,
owner_id: 1,
name: "name",
}
Below is the algorithm,
group = () => {
const self = [];
const others = [];
for each item
if item is uploaded by current_user
self.push(item)
else
others.push(item)
return {self, others}
}
How can i implement the above in react or javascript. Could someone help me with this. thanks.
A much better aproach is to use filter as follows
const group = () => {
const items = [
{
id: 0,
owner_id: 1,
name: "name",
},
{
id: 2,
owner_id: 2,
name: "user 2",
}
];
let current_user = { id: 1, name: "current user"}
const result = items.filter(item => item.owner_id != current_user.id);
const result2 = items.filter(item => item.owner_id == current_user.id);
return { result, result2}
}
There are a couple ways to approach this problem. I think the cleanest approach in terms of readability and length is to leverage Javascript's built in prototype Array.filter() method.
const self = all_items.filter(item => item.owner === current_user);
const others = all_items.filter(item => item.owner !== current_user);
Or for a solution that mirrors your example algorithm more closely, you can iterate over all_items with forEach() and push values to self and others as you go.
const self = [];
const others = [];
all_items.forEach(item => {
if (item.owner === current_user) {
self.push(item);
} else {
others.push(item);
}
});
**Also note that === will compare both type and value.
You can use filter
var all_items = [{
id: 0,
owner_id: 1,
name: "Matt",
},
{
id: 1,
owner_id: 2,
name: "Dave",
},
{
id: 2,
owner_id: 1,
name: "Mike",
},
{
id: 3,
owner_id: 3,
name: "Jack",
},
{
id: 4,
owner_id: 1,
name: "Paul",
}];
var current_user = {
id: 1
};
// self
console.log(all_items.filter(function(item){
return item.owner_id === current_user.id;
}));
// others
console.log(all_items.filter(function(item){
return item.owner_id !== current_user.id;
}));

Get list of duplicate objects in an array of objects

I am trying to get duplicate objects within an array of objects. Let's say the object is like below.
values = [
{ id: 10, name: 'someName1' },
{ id: 10, name: 'someName2' },
{ id: 11, name: 'someName3' },
{ id: 12, name: 'someName4' }
];
Duplicate objects should return like below:
duplicate = [
{ id: 10, name: 'someName1' },
{ id: 10, name: 'someName2' }
];
You can use Array#reduce to make a counter lookup table based on the id key, then use Array#filter to remove any items that appeared only once in the lookup table. Time complexity is O(n).
const values = [{id: 10, name: 'someName1'}, {id: 10, name: 'someName2'}, {id: 11, name:'someName3'}, {id: 12, name: 'someName4'}];
const lookup = values.reduce((a, e) => {
a[e.id] = ++a[e.id] || 0;
return a;
}, {});
console.log(values.filter(e => lookup[e.id]));
Let's say you have:
arr = [
{ id:10, name: 'someName1' },
{ id:10, name: 'someName2' },
{ id:11, name: 'someName3' },
{ id:12, name: 'someName4' }
]
So, to get unique items:
unique = arr
.map(e => e['id'])
.map((e, i, final) => final.indexOf(e) === i && i)
.filter(obj=> arr[obj])
.map(e => arr[e]);
Then, result will be
unique = [
{ id:10, name: 'someName1' },
{ id:11, name: 'someName3' },
{ id:12, name: 'someName4' }
]
And, to get duplicate ids:
duplicateIds = arr
.map(e => e['id'])
.map((e, i, final) => final.indexOf(e) !== i && i)
.filter(obj=> arr[obj])
.map(e => arr[e]["id"])
List of IDs will be
duplicateIds = [10]
Thus, to get duplicates objects:
duplicate = arr.filter(obj=> dublicateIds.includes(obj.id));
Now you have it:
duplicate = [
{ id:10, name: 'someName1' },
{ id:10, name: 'someName2' }
]
Thanks https://reactgo.com/removeduplicateobjects/
You haven't clarified whether two objects with different ids, but the same "name" count as a duplicate. I will assume those do not count as a duplicate; in other words, only objects with the same id will count as duplicate.
let ids = {};
let dups = [];
values.forEach((val)=> {
if (ids[val.id]) {
// we have already found this same id
dups.push(val)
} else {
ids[val.id] = true;
}
})
return dups;
With lodash you can solve this with filter and countBy for complexity of O(n):
const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]
const counts = _.countBy(data, 'id')
console.log(_.filter(data, x => counts[x.id] > 1))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
You could do the same with ES6 like so:
const data = [{ id: 10,name: 'someName1' }, { id: 10,name: 'someName2' }, { id: 11,name: 'someName3' }, { id: 12,name: 'someName4' } ]
const countBy = (d, id) => d.reduce((r,{id},i,a) => (r[id] = a.filter(x => x.id == id).length, r),{})
const counts = countBy(data, 'id')
console.log(data.filter(x => [x.id] > 1))
You can use an array to store unique elements and use filter on values to only return duplicates.
const unique = []
const duplicates = values.filter(o => {
if(unique.find(i => i.id === o.id && i.name === o.name)) {
return true
}
unique.push(o)
return false;
})
With lodash you can use _.groupBy() to group elements by their id. Than _.filter() out groups that have less than two members, and _.flatten() the results:
const values = [{id: 10, name: 'someName1'}, {id: 10, name: 'someName2'}, {id: 11, name:'someName3'}, {id: 12, name: 'someName4'}];
const result = _.flow([
arr => _.groupBy(arr, 'id'), // group elements by id
g => _.filter(g, o => o.length > 1), // remove groups that have less than two members
_.flatten // flatten the results to a single array
])(values);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
An alternative based in #ggorlen solution with new Map() as accumulator (for better performance) and without unary operator ++ (not advised by default in projects with ESLint).
const values = [{ id: 10, name: "someName1" }, { id: 10, name: "someName2" }, { id: 11, name: "someName3" }, { id: 12, name: "someName4" },];
const lookup = values.reduce((a, e) => {
a.set(e.id, (a.get(e.id) ?? 0) + 1);
return a;
}, new Map());
console.log(values.filter(e => lookup.get(e.id) > 1));
Try this
function checkDuplicateInObject(propertyName, inputArray) {
var seenDuplicate = false,
testObject = {};
inputArray.map(function(item) {
var itemPropertyName = item[propertyName];
if (itemPropertyName in testObject) {
testObject[itemPropertyName].duplicate = true;
item.duplicate = true;
seenDuplicate = true;
}
else {
testObject[itemPropertyName] = item;
delete item.duplicate;
}
});
return seenDuplicate;
}
referred from : http://www.competa.com/blog/lets-find-duplicate-property-values-in-an-array-of-objects-in-javascript/

Comparing two Objects by id and creating the new one

So I have two objects with this structure:
const obj1 = { data:
[ {
id: 1,
name: 'Linda'
},
{
id: 2,
name: 'Mark'
}
];
const obj2 = [
{
id: 1,
salary: "2000, 60 USD"
},
undefined
],
[
{
id: 2,
salary: "4000, 50 USD"
},
undefined
]
I need to make a function to combine both of these into one object, based on id.
So the final results would be:
const finalObj = { data:
[ {
id: 1,
name: 'Linda',
salary: "2000, 60 USD"
},
{
id: 2,
name: 'Mark',
salary: "4000, 50 USD"
}
];
I have checked other questions, but could not find anything that would help. It can be done with lodash afaik, but don't know how.
I have tried the following:
finalObj = obj1.data.map(x => {
return {
...x,
...obj2
}
But it didn't map correctly.
Thanks.
EDIT: Updated obj2 response.
You can array#concat both your array and then using array#reduce and an object lookup with id, merge your objects. Then return all the values from this object.
const obj1 = { data: [{ id: 1, name: 'Linda' }, { id: 2, name: 'Mark' }]},
obj2 = { data: [{ id: 1, salary: "2000, 60 USD"}, { id: 2, salary: "4000, 50 USD"}]},
result = Object.values(obj1.data.concat(obj2.data).reduce((r,o) => {
r[o.id] = r[o.id] || {};
r[o.id] = {...r[o.id], ...o};
return r;
},{}));
console.log(result);
You could take a Map for collecting all properties of the same id in an object. Later get the values of the map.
const join = o => o && map.set(o.id, Object.assign(map.get(o.id) || {}, o));
var obj1 = { data: [{ id: 1, name: 'Linda' }, { id: 2, name: 'Mark' } ]},
obj2 = [{ id: 1, salary: "2000, 60 USD" }, undefined, { id: 2, salary: "4000, 50 USD" }, undefined],
map = new Map,
result;
obj1.data.forEach(join);
obj2.forEach(join);
result = { data: Array.from(map.values()) };
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another way
const res = {
...obj1, // take the initial object
data: obj1.data.map(item => ({ // rewrite data property by iterate each item
// and merge item with corresponding
// object from obj2
...item, // take the item object
...obj2.find(({ id }) => id === item.id) // find corresponding object
}))
};
Here is an approach which would combine the objects and not overwrite the properties but only add the ones that are missing as well as avoid the undefined etc:
const names = {data: [{ id: 1, name: 'Linda' },{ id: 2, name: 'Mark' }]}
const salaries = [{ id: 1, salary: "2000, 60 USD" }, undefined]
var result = _.mapValues(names.data, x => {
let hit = _.find(salaries, y => y ? y.id === x.id : null)
return hit ? _.defaults(x, hit) : x
})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
We are using mapValues to get to the values of names.data and look through them and for each of them get a hit in the salaries. If the hit exists we default the props of the hit with the current data object and return. Hope this helps.

Categories

Resources