I have an array of objects and an array of primitive values. I want to create a new array of objects that maps the values of the first to the latter.
Here's the array of objects:
var eventInstances = [
{
id: 1,
title: "Item 1"
},
{
id: 2,
title: "Item 2"
},
{
id: 1,
title: "Item 3"
},
{
id: 3,
title: "Item 4"
},
]
And the array of primitive values:
var dates = [1, 2, 3]
I want map the objects of eventInstances to a new Array of objects with the values of dateInstances as keys, which would correspond with the value of id in eventInstances.
The result should be:
var dateInstances = [
{
id: 1,
instances: [
{
title: "Item 1"
},
{
title: "Item 1"
}
]
},
{
id: 2,
instances: [
{
title: "Item 1"
},
{
title: "Item 1"
}
]
},
{
id: 3,
instances: [
{
title: "Item 2"
}
]
}
];
Sorry, if this is a newbie question, I've been reading up on sorting methods, but I'm quite at a loss here. Any hint would be highly appreciated. Thanks!
This function will give you your expected result.
dates.map(id=>{
return {id:id,
instances:eventInstances.filter(item =>{
return item.id === id;
})
.map(foundItem => {
return {title: foundItem.title}
})
}});
Might be a simpler way to do it, but here's what's happening. Use map to iterate through your dates array. Then filter to find items in eventInstances that match, then map through those again to just return the title.
Array.map docs
Array.filter docs
You actually don't need the second array, as all those id can be found in the data.
You could collect the data in a map keyed by id and then extract the values:
const eventInstances = [{id: 1,title: "Item 1"},{id: 2,title: "Item 2"},{id: 1,title: "Item 3"},{id: 3,title: "Item 4"}];
const map = new Map(eventInstances.map(({id}) => [id, {id, instances: []}]));
eventInstances.forEach(({id, title}) => map.get(id).instances.push({ title }));
const result = [...map.values()];
console.log(result);
This creates a Map from the data. The Map is populated using its constructor argument, which can accept an array of pairs as input. Such a pair will serve as key/value pair in the Map being constructed. The pairs that are given to the constructor look like this:
[id, {id, instances: []}]
And so the Map will have its keys set to ids and its values will be objects in the form {id, instances: []}. Duplicate id values will not result in extra entries... they will be ignored in the process.
The next step is the forEach loop, which puts values inside those instances properties.
Finally, the keys of the Map have served their purpose, they can now be ejected. We only need the values, which are turned into an array through the spread syntax.
I think you are looking for an object where the key equals to the id, and the value equals to an array of titles, like:
{
"0":[
"title1",
"title2"
],
"1":[
"title1",
"title2"
],
}
To achieve that you need:
var dateInstances = {};
for(let i =0; i<eventInstances.length;i++){
if (!Array.isArray(dateInstances[eventInstances[i]["id"]])){
dateInstances[eventInstances[i]["id"]] = [];
}
dateInstances[eventInstances[i]["id"]].push(eventInstances[i]["id"]["title"]);
}
Related
I currently have an array of objects that look like this but with a ton more entries,
[
{
owningrep: "Some name",
id: 1,
emails: "email#address.com;shane#emails.com"
},
{
owningrep: "Other name",
id: 2,
emails: "me#emailstuff.com"
}
]
I also provide the option to import a CSV of emails, which I then take all of the values and put them in an array.
My question is, given this array of objects, and this array of CSV values, how would I then be able to filter the array of objects to NOT include objects where any of the emails in the csv appear in the email value? Keep in mind some objects might have one email, others might have multiple separated by a semicolon.
Thanks in advance
I've attempted to simply filter the array with includes, but that only seems to cut off a few entries.
let inc = inclusionsList.value.length > 0 && inclusionsList.value['0'] != 0 formatDataAsArray(data).filter(d => _.includes(inclusionsList.value, d.id)) : data;
let fromCSV = formatDataAsArray(inc).filter(i => !_.includes(exclusionCSV.value, i.Emails));
Ultimately what I want to do is take an array of objects like:
[
{
owningrep: "Some name",
id: 1,
emails: "email#address.com;shane#emails.com"
},
{
owningrep: "Other name",
id: 2,
emails: "me#emailstuff.com"
}
]
And an array of emails like:
["crona.audreanne#denesik.com", "minerva.leannon#pfannerstill.info", "barton.eloise#yahoo.com", "rachelle.rau#hotmail.com", "ihaley#morar.com", "ggleichner#kirlin.info", "keely.ledner#yahoo.com", "jerel05#yahoo.com", "eleonore35#murphy.info", "ivory56#hotmail.com", "email#address.com"]
And filter the array of objects so that the only objects left are ones whose email key does not include any of the emails in the array.
If I understrand well your problem and your data here is my proposition:
const exclusionCSV = {value: ['mail1', 'me#emailstuff.com']}
const inclusionList = {value: [
{
owningrep: "Some name",
id: 1,
emails: "email#address.com;shane#emails.com"
},
{
owningrep: "Other name",
id: 2,
emails: "me#emailstuff.com"
}
]}
const setExclusionMail = new Set(exclusionCSV.value)
const result = inclusionList.value.filter(({emails}) => {
const mails = emails.split(';')
return !mails.some(m => setExclusionMail.has(m))
})
So I have a series of objects that are pulled from an API and inputted into an array, something like such:
array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 1, name: "Second", relationship: "Friend"}
]
The user is allowed to add and remove objects to the list freely (they will appear within a Vue.JS DataTable), and said user is allowed a maximum of 4 objects within the array (lets say 4 "friends")
How should I go about implementing a function that searches the existing array (say, if its populated from the API), and inputs the new object with the corresponding ID that is missing (so if the user deletes the object with the id 2, and adds another, it will search said array with objects, find the missing id 2 slot in the array, and input the object in its place)?
Previously I have gone about it via implement array.find() with conditionals to see if the array contains or does not contain the certain id value, however, it searches through each entry and can end up inserting the same object multiple times. Another method I haven't attempted yet would be having a separate map that contains ids, and then when a user removes an object, having it correspond with the map, and vice versa when adding.
Any suggestions? Thanks
Instead of an array, I'd keep an object in data. Have it keyed by id, like this:
let objects = {
0: { id: 0, name: 'name0', relationship: 'relationship0' },
1: { id: 1, name: 'name1', relationship: 'relationship1' },
}
Integer keys in modern JS will preserve insertion order, so you can think of this object as ordered. The API probably returns an array, so do this...
// in the method that fetches from the api
let arrayFromApi = [...];
this.objects = array.reduce((acc, obj) => {
acc[obj.id] = obj; // insertion order will be preserved
return acc;
}, {});
Your UI probably wants an array, so do this (refer to "array" in the markup):
computed: {
array() {
return Object.values(this.objects);
},
To create a new object, insert it in order, minding the available keys. Note this is a linear search, but with small numbers of objects this will be plenty fast
methods: {
// assumes maxId is const like 4 (or 40, but maybe not 400)
createObject(name, relationship) {
let object = { name, relationship };
for (let i=0; i< maxId; i++) {
if (!this.objects[i]) {
object.id = i;
this.objects[i] = object;
break;
}
}
try this,
let array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 4, name: "Second", relationship: "Friend"},
{id: 2, name: "Second", relationship: "Friend"},
]
const addItem = (item) => {
let prevId = -1
// this is unnecessary if your array is already sorted by id.
// in this example array ids are not sorted. e.g. 0, 4, 2
array.sort((a, b) => a.id - b.id)
//
array.forEach(ob => {
if(ob.id === prevId + 1) prevId++
else return;
})
item = {...item, id: prevId + 1 }
array.splice(prevId+1, 0, item)
}
addItem({name: "x", relationship: "y"})
addItem({name: "a", relationship: "b"})
addItem({name: "c", relationship: "d"})
console.log(array)
You can simply achieve this with the help of Array.find() method along with the Array.indexOf() and Array.splice().
Live Demo :
// Input array of objects (coming from API) and suppose user deleted 2nd id object from the array.
const arr = [
{id: 0, name: "First", relationship: "Friend" },
{id: 1, name: "Second", relationship: "Friend" },
{id: 3, name: "Fourth", relationship: "Friend" }
];
// find the objects next to missing object.
const res = arr.find((obj, index) => obj.id !== index);
// find the index where we have to input the new object.
const index = arr.indexOf(res);
// New object user want to insert
const newObj = {
id: index,
name: "Third",
relationship: "Friend"
}
// Insert the new object into an array at the missing position.
arr.splice(index, 0, newObj);
// Output
console.log(arr);
I have an array of objects and I want to multiply a first key value in second key value and then remove the second key for each object element.
I have an array like this:
[
{ id:1, price:2, amount:4, numberBuy: 3 },
{ id:2, price:3, amount:5, numberBuy: 2 },
]
and after that have to become like this:
[
{ id:1, price:2, amount:12 },
{ id:2, price:3, amount:10 },
]
I strictly love to using it by map method if its possible maybe your method can help me even in learning it. Thanks
Make use of map and return each modified object.
const newArray = [
{ id: 1, price: 2, amount: 4, numberBuy: 3 },
{ id: 2, price: 3, amount: 5, numberBuy: 2 }
].map(({ id, price, amount, numberBuy}) => ({
id,
price,
amount: amount * numberBuy,
}));
I am having this array of object
let detail : [
0: {
Code: "Code 1"
Price: "0.00"
},
1: {
Code: "Code 2"
Price: "9.00"
}
]
I want to store the price in an array(for eg: result) so that I can merge it with another existing array of the object(for eg: alldetail)
result = [
0: {
Price:"0.00"
},
1: {
Price:"9.00"
},
]
Using map() method which creates a new array filled with the results of the provided function executing on every element in the calling array.
So, in your case, you'll return an object with the key Price and the value will be the current object with the value of it's Price property.
let detail = [
{
Code: "Code 1",
Price: "0.00"
},
{
Code: "Code 2",
Price: "9.00"
}
];
let result = detail.map(current => {return {Price: current.Price}});
console.log(result);
Use map to create a new array of objects.
const detail = [
{ Code: "Code 1", Price: "0.00" },
{ Code: "Code 2", Price: "9.00" }
];
const result = detail.map(({ Price }) => ({ Price }));
console.log(result);
Additional documentation
Destructuring assignment.
I have an array of objects like this:
[
{ name: "Group 1", value: "Foo" },
{ name: "Group 2", value: "Bar" },
{ name: "Group 1", value: "Baz" }
]
I'd like to use Partial Lenses library to transform these groups to keys of an object with corresponding group's items, like this:
{
"Group 1": [
{ name: "Group 1", value: "Foo" },
{ name: "Group 1", value: "Baz" }
],
"Group 2": [
{ name: "Group 2", value: "Bar" }
]
}
My current approach is like this, assuming I have the source data in a variable called data:
const grouped = L.collect([L.groupBy('name'), L.entries], data)
const setKey = [L.elems, 0]
const getName = [L.elems, 1, 0, 'name']
const correctPairs = L.disperse(setKey, L.collectTotal(getName, grouped), grouped)
L.get(L.inverse(L.keyed), correctPairs)
I don't like that I need to use the grouped and correctPairs variables to hold data, as I probably should be able to do the transformation directly in the composition. Could you help me to compose the same functionality in a more meaningful way?
Here's a Partial Lenses Playground with the above code.
I assume the goal is to actually create an isomorphism through which one can
view such an array as an object of arrays and also perform updates. Like a
bidirectional version of e.g. Ramda's
R.groupBy function.
Indeed, one approach would be to just use Ramda's
R.groupBy to implement a new primitive
isomorphism using L.iso.
Something like this:
const objectBy = keyL => L.iso(
R.cond([[R.is(Array), R.groupBy(L.get(keyL))]]),
R.cond([[R.is(Object), L.collect([L.values, L.elems])]])
)
The conditionals are needed to allow for the possibility that the data is not of
the expected type and to map the result to undefined in case it isn't.
Here is a playground with the above Ramda based
objectBy
implementation.
Using only the current version of Partial Lenses, one way to compose a similar
objectBy combinator would be as follows:
const objectBy = keyL => [
L.groupBy(keyL),
L.array(L.unzipWith1(L.iso(x => [L.get(keyL, x), x], L.get(1)))),
L.inverse(L.keyed)
]
Perhaps the interesting part in the above is the middle part that converts an
array of arrays into an array of key-array pairs (or the other way around).
L.unzipWith1
checks that all the keys within a group match, and if they don't, that group
will be mapped to undefined and filtered out by
L.array. If desired,
it is possible to get stricter behaviour by using
L.arrays.
Here is a playground with the above composed
objectBy
implementation.
You don't need any library, use a generic function that returns a reducer, that way you can use to group any collection with any key. In the example below I used this to group by name, but also by value.
const groupBy = key => (result,current) => {
let item = Object.assign({},current);
// optional
// delete item[key];
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const data = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
const grouped = data.reduce(groupBy('name'),{});
console.log(grouped);
const groupedByValue = data.reduce(groupBy('value'),{});
console.log(groupedByValue);
You can use Array.reduce
let arr = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
let obj = arr.reduce((a,c) => Object.assign(a, {[c.name]: (a[c.name] || []).concat(c)}), {});
console.log(obj);