Group values keys based for each other value key - javascript

Sorry for bad title, I don't really know how to phrase this and this might be trivial problem ...
The data that comes from the array looks like this, each name can have an indefinite amount of sequence, what I want to do is group them by name and put each sequence in an array
[
{
name: 'Mike',
sequence: 'AAAA',
},
{
name: 'Bob',
sequence: 'ABAB',
},
{
name: 'Bob',
sequence: 'AAAB',
},
{
name: 'Marvin',
sequence: 'AAAA',
},
{
name: 'Marvin',
sequence: 'AABA',
},
{
name: 'Marvin',
sequence: 'BBBB',
},
]
What I am looking to return for each name by using console.log(name, array) for example would be something like this
Mike ["AAAA"]
Bob ["ABAB","AAAB"]
Marvin ["AAAA","AABA","BBBB"]
Thank you very much!

As mentioned in the comments, it seems you have tried some ways to solve the problem.
You can try following solution
Use Array.reduce to convert your array into an object with keys as name and value as array of sequences
In the reduce function, check whether the name exist in the resultant object. If it exists, concat the sequence to it (using spread syntax) else add a new entry with an array with sequence.
let input = [{name:'Mike',sequence:'AAAA',},{name:'Bob',sequence:'ABAB',},{name:'Bob',sequence:'AAAB',},{name:'Marvin',sequence:'AAAA',},{name:'Marvin',sequence:'AABA',},{name:'Marvin',sequence:'BBBB',}];
let result = input.reduce((a, {name, sequence}) => Object.assign(a, {[name] : a[name] ? [...a[name], sequence]: [sequence]}), {});
console.log(result);

inputArray.reduce((acc,{name,sequence}) => {
let obj = acc.find(a => a.name === name);
obj ? obj.sequence.push(sequence)
: acc.push({name,sequence:[sequence]});
return acc;
}, [])

Related

JS - How to add key:value pairs from objects nested in arrays to other objects nested in another array

I know it has been countlessly asked and I assure you that I've read a lot of posts, articles, etc., and watched a lot of videos but nothing seems to click.
so there we go :
Here are 2 arrays with partial information about every person
let arr1 = [{id:00, name:Ben, city:Philadelphia}, {id:01, name:Alice, city:Frankfurt}, {id:02, name:Detlef, city:Vienna}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
And there is the desired final result: an array including the name, city, and age of each person
let arr3 = [{name:Ben, city:Philadelphia, age:39}, {name:Alice, city:Frankfurt, age:75 }, {name:Detlef, city:Vienna, age:18}]
What's the situation? Two arrays both containing objects. each nested object has an id. That id is the common key in each array of objects.
What do you want to do? : I want to create a third array including information from both arrays (from arr1: name and city; from arr2:age).
What have you tried so far? : I couldn't manage to achieve anything worth showing. this minimal example is intended to show you a simple example of my current situation which is: I've got an array that is in the LocalStorage on one hand and an API on the other, both contain some info regarding particular objects (let's say, persons). I want to create an array that will contain all the information regarding each person for easier manipulation afterward (DOM generation, etc.).
I've managed to store both arrays in two "local" arrays but the problem is still there: I can't figure out how to make an array where items are getting their key/value from two separate sources.
Thank you for your help!
You can use reduce method on the arr with array as an inital value, and inside try to find the corrospending item with same id and destruct the object from the id and merge the two object with spread operator.
let arr1 = [{id:00, name:'Ben', city: 'Philadelphia' }, {id:01, name:'Alice', city:'Frankfurt'}, {id:02, name:'Detlef', city:'Vienna'}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
const result = arr1.reduce((acc, { id: id1, ...rest1 }) => {
const { id: id2, ...rest2 } = arr2.find(i => i.id === id1)
acc.push({ ...rest1, ...rest2 })
return acc;
}, [])
console.log(result)
You can solve it in various ways, here first I have implemented a dict with key as id to get the value in O(1) while iterating arr2.
So the overall time complexity is O(n+k) where n is len of arr1 and k is len of arr2.
let arr1 = [{id:00, name: "Ben", city: "Philadelphia"}, {id:01, name:"Alice", city:"Frankfurt"}, {id:02, name:"Detlef", city:"Vienna"}];
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}];
const refMapById = arr1.reduce((refMap, {id, name, city}) => {
refMap[id] = {name, city};
return refMap;
}, {});
const result = arr2.reduce((resultArray, {id, age}) => [...resultArray, { ...refMapById[id],age}], []);
console.log(result);
Cheers!
It will be worth creating a dictionary from one of the arrays anyway since using .find() inside of .reduce() adds an unnecessary nested loop. But instead of reducing the second array as was suggested you can simply .map() it into the result array, like so:
let arr1 = [{ id: 00, name: "Ben", city: "Philadelphia" }, { id: 01, name: "Alice", city: "Frankfurt" }, { id: 02, name: "Detlef", city: "Vienna" }];
let arr2 = [{ id: 02, age: 18 }, { id: 00, age: 39 }, { id: 01, age: 75 }];
const groupedById = arr1.reduce((group, person) => {
group[person.id] = person;
return group;
}, {});
const result = arr2.map((personPartFromSecondArray) => {
const personPartFromFirstArray = groupedById[personPartFromSecondArray.id];
if (typeof personPartFromFirstArray !== "undefined") {
return { ...personPartFromFirstArray, ...personPartFromSecondArray }
}
return personPartFromSecondArray;
});
console.log(result);

Remove objects from array where an attribute is equal to specific string

I am using an array.filter() function to remove all the objects where one of their attribute is equal to any of the string in a given array.
The objects in the array are crypto trades and I need to filter out the trades with the trade pairs that I do not want. How would I achieve this using the filter function?
For now, I tried this which did not work evidently:
filteredPairs = filteredPairs.filter(
(pair) =>
!pair.symbol.includes(
"USDTBUSD",
"USDTUSDC",
"USDTUST",
"USDTUSDP",
"USDTDAI",
"BUSDUSDT",
"BUSDUSDC",
"BUSDUST",
"BUSDUSDP",
"BUSDDAI",
"USDCUSDT",
"USDCBUSD",
"USDCUST",
"USDCUSDP",
"USDCDAI",
"USTUSDT",
"USTBUSD",
"USTUSDC",
"USTUSDP",
"USTDAI",
"USDPUSDT",
"USDPBUSD",
"USDPUSDC",
"USDPUST",
"USDPDAI",
"DAIUSDT",
"DAIBUSD",
"DAIUSDC",
"DAIUSDP",
"DATUST"
)
);
This is not filtering out these pairs. Any insight would be helpful. Thank you.
This can be done in a single line.
// testing object
const filteredPairs = [
{
symbol: 'USDTBUSD',
},
{
symbol: 'abc',
},
{
symbol: 'BUSDUSDT',
},
{
symbol: '321',
},
];
// items we don't want
const blacklist = [
'USDTBUSD',
'USDTUSDC',
'USDTUST',
'USDTUSDP',
'USDTDAI',
'BUSDUSDT',
'BUSDUSDC',
'BUSDUST',
'BUSDUSDP',
'BUSDDAI',
'USDCUSDT',
'USDCBUSD',
'USDCUST',
'USDCUSDP',
'USDCDAI',
'USTUSDT',
'USTBUSD',
'USTUSDC',
'USTUSDP',
'USTDAI',
'USDPUSDT',
'USDPBUSD',
'USDPUSDC',
'USDPUST',
'USDPDAI',
'DAIUSDT',
'DAIBUSD',
'DAIUSDC',
'DAIUSDP',
'DATUST',
];
// filter
const newFilteredPairs = filteredPairs.filter(({ symbol }) => !blacklist.some((item) => symbol.includes(item)));
console.log(newFilteredPairs);

How to check if property of an objects of array matches with one of the values in another array of object

I know the header is way too complicated but that's how it is right now. Let me make it more clear for you.
There is an object like
const users= [
{
id:"1",
name:"John",
mail:"aaa#gmail.com",
},
{
id:"2",
name:"Joe",
mail:"bbb#gmail.com",
},
]
Then there is
const attendingUsers = [
{
id:"1",
name:"John",
mail:"aaa#gmail.com",
.....
},
{
id:"2",
name:"Joe",
mail:"bbb#gmail.com",
.....
},}
] 
Both of the arrays has different properties and I just want to get the ones that are important to me. What I need is to look through users array and find the ones that has the same ids as the ones from attendingUsers.
I have came up with users.filter(user => user.id == attendingUsers.map(attendingUser => attendingUser.id)); but that is simply returning empty array. Any idea what would be the best way to tackle this sort of a problem?
First off, you'll have to make sure if the ID types are correct. Users has Number type for IDs but attendingUsers has String type.
Let's say they're both the same type for the code below (I'm going with string).
You can turn the attendingUsers array into an array of strings with:
const attendingUsersIds = attendingUsers.map(attendingUser => attendingUser.id)
Then match the ids with:
const matchedUsers = users.filter(user => attendingUsersIds.includes(user.id))
If they're intended to not be the same type, you can use user.id.toString() to turn the Number into a String or parseInt(attendingUser.id) to turn the String into a Number.
We can use Array.map to create a new array of users, with a property isAttending added to each user.
We determine if they are attending by using Array.some to search for any matching attendee with the same id.
const users = [
{
id:1,
name:"John",
mail:"aaa#gmail.com",
},
{
id:2,
name:"Joe",
mail:"bbb#gmail.com",
},
{
id:3,
name:"Alice",
mail:"ccc#gmail.com",
}
]
const attendingUsers = [
{
id:"1",
name:"John",
mail:"aaa#gmail.com",
},
{
id:"2",
name:"Joe",
mail:"bbb#gmail.com",
}
]
const result = users.map(user => {
return { ...user, isAttending: attendingUsers.some(({id}) => id == user.id) };
});
console.log("Users (with attending property):", result);

Match array value with value in an array of objects javascript

I am trying to work out how I can return a list with values from the own key in the array bellow if the object name value matches values in the lookupvalues array
lookupvalues = ["ross","linda"]
resources = [{own: "car", name: "bob"},{own: "bike", name: "ross"},{own: "plane", name: "linda"}]
wanted_output = ["bike","plane"]
I am struggling a bit with a good method to use for when I need to compare value in an object with array values. Is there a reasonable straight forward way to do this?
I must say how impressed I am that I got 4 replies with working examples at the same time!
One way (array method chaining) is that you could filter by name and map to grap each's own
const lookupvalues = ["ross", "linda"]
const resources = [
{ own: "car", name: "bob" },
{ own: "bike", name: "ross" },
{ own: "plane", name: "linda" },
]
const res = resources
.filter(({ name }) => lookupvalues.includes(name))
.map(({ own }) => own)
console.log(res)
resources.filter(resource => lookupvalues.includes(resource.name))
.map(resource => resource.own);
This will filter by the items that have names that are included in lookupvalues, and then transform the array into an array of the own values of those remaining.
You can take the help of Array#filter and Array#map:
const lookupvalues = ["ross","linda"]
const resources = [{own: "car", name: "bob"},{own: "bike", name: "ross"},{own: "plane", name: "linda"}]
const filterRes = (arr) => {
const lookup = new Set(lookupvalues);
return arr.filter(({name}) => lookup.has(name))
.map(({own}) => own);
}
console.log(filterRes(resources));
resources.filter(item => lookupvalues.indexOf(item.name) > -1).map(item => item.own)

Fastest way to filter object by multiple properties

I have an array of objects that I want to filter for a string. So I want to check multiple properties if they contain the filter string (case insensitive).
Here's the array:
[{
id: "01234",
name: "My Object 01234",
short_name: "MO01234"
}, ...]
So all of the following filter strings should match that object: 0123, obj, mO01 etc.
Here's what I have right now:
const filterString = this.filterString.toLowerCase();
return myObjects.filter(
entry => {
return
entry.id.toLowerCase().indexOf(filterString) >= 0 ||
entry.name.toLowerCase().indexOf(filterString) >= 0 ||
entry.short_name.toLowerCase().indexOf(filterString) >= 0;
}
);
Can you think of a faster/cleaner way to do that?
I don't think that you can do it faster, but cleaner may be something like that
const filterString = this.filterString.toLowerCase();
return myObjects.filter((entry) => {
return Object.values(entry).some((value) => {
return value.toLowerCase().includes(filterString)
})
});
If you are allowed to put additional properties in your object, perhaps you could concatenate id, name and short_name (already in lowercase) into a single string and store it in the object as e.g. search_key; then you'd only have to check that.
{
id: "01234",
name: "My Object 01234",
short_name: "MO01234",
search_key: "01234:my object 01234:mo01234"
}
return myObjects.filter(
entry => entry.search_key.indexOf(filterString) >= 0
);
One thing you have to be mindful of in this case is to prevent unintended matches that may arise because e.g. the last few characters of id and the first few characters of name together produce a match. This is why I used a : delimiter here, assuming that's a character that can't appear in an ID or a short name.
let objects = [{
id: "01234",
name: "My Object 01234",
short_name: "MO01234"
},
{
id: "test",
name: "test",
short_name: "test"
}];
const filter = (collection, searchFor) => {
return collection.filter(obj => Object.values(obj).reduce((a,b) => a || String(b).toLowerCase().indexOf(searchFor.toLowerCase()) > -1, false))
}
console.log(filter(objects, "0123"));
console.log(filter(objects, "obj"));
console.log(filter(objects, "mO01"));
You could also extend this function to take a set of columns as parameter to filter on.
Another version using Regex:
const filterRegex = (collection, searchFor) => {
return collection.filter(obj => Object.values(obj).reduce((a,b) => a || String(b).match(new RegExp(searchFor, 'gi')), false))
}
console.log(filterRegex(objects, "0123"));
console.log(filterRegex(objects, "obj"));
console.log(filterRegex(objects, "mO01"));

Categories

Resources