Reconstruct an array of objects in javascript that contains nested arrays - javascript

I'm struggling of coping with an issue here.
lets suppose I have an array of objects like this:
[
{name:Alex, products: [{type: 1, code: 1213}, {type: 2, code: 2312}]},
{name:Alex, products: [{type: 1, code: 1213}, {type: 2, code: 2312}]}
]
I would like somehow to reconstruct my object to be something like this:
[
{name:Alex, products: [{name:Alex, type: 1, code: 1213}, {name:Alex, type: 2, code: 2312}]},
{name:Alex, products: [{{name:Alex, type: 1, code: 1213}, {{name:Alex, type: 2, code: 2312}]}
]
so each nested array contains the name. Is that possible in javascript?

You can use map() method with spread syntax in object to create new array with updated objects and keep original data.
const data = [
{name:'Alex', products: [{type: 1, code: 1213}, {type: 2, code: 2312}]},
{name:'Alex', products: [{type: 1, code: 1213}, {type: 2, code: 2312}]}
]
const result = data.map(e => ({
...e,
products: e.products.map(p => {
return {...p, name: e.name}
})
}))
console.log(result)

I want somehow to reconstruct my object so as to be something like
this:
Use map
arr.map( s => (s.products.map( i => (i.name = s.name, i) ), s) );
Demo
var arr = [{
name: "Alex",
products: [{
type: 1,
code: 1213
}, {
type: 2,
code: 2312
}]
},
{
name: "Alex",
products: [{
type: 1,
code: 1213
}, {
type: 2,
code: 2312
}]
}
]
var output = arr.map(s => (s.products.map(i => (i.name = s.name, i)), s));
console.log(output);

You could create new array/objects with Object.assign.
var data = [{ name: 'Alex', products: [{ type: 1, code: 1213 }, { type: 2, code: 2312 }] }, { name: 'Alex', products: [{ type: 1, code: 1213 }, { type: 2, code: 2312 }] }],
converted = data.map(o => Object.assign(
{},
o,
{ products: o.products.map(p => Object.assign({ name: o.name }, p)) }
));
console.log(converted);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can use nested Array.map() calls with Object.assign() to create the new array without changing the original data:
const data = [{"name":"Alex","products":[{"type":1,"code":1213},{"type":2,"code":2312}]},{"name":"Alex","products":[{"type":1,"code":1213},{"type":2,"code":2312}]}]
const result = data.map((o) => Object.assign({}, o, {
products: o.products.map((p) => Object.assign({ name: o.name }, p))
}))
console.log(result)
If you just want to change (mutate) the current array, use nested Array.forEach() calls:
const data = [{"name":"Alex","products":[{"type":1,"code":1213},{"type":2,"code":2312}]},{"name":"Alex","products":[{"type":1,"code":1213},{"type":2,"code":2312}]}]
data.forEach((o) => o.products.forEach((p) => p.name = o.name));
console.log(data)

You have typo in name property.Alex should be 'Alex' (string).You can get help from two array methods. Array.prototype.map() and Array.prototype.forEach() to achieve your goal
var initialArr = [
{name:'Alex1', products: [{type: 1, code: 1213}, {type: 2, code: 2312}]},
{name:'Alex2', products: [{type: 1, code: 1213}, {type: 2, code: 2312}]}
]
var newArr = initialArr.map(function(elem){
elem.products.forEach(function(obj){
obj.name = this.name
},elem)
return elem
})
console.log(newArr)

Related

How to filter items from array of objects based on another array of strings using javascript?

i want to filter the array of objects based on array of strings using javascript.
i have input array of object like so,
const input = [
{
id: 1,
name: 'first',
type: 'first_type',
},
{
id: 2,
name: 'second',
type: 'second_type',
},
{
id: 3,
name: 'third',
type: 'third_type',
},
];
const chosen_items = ['1','2']
now i want to filter the items in input whose id match with chosen_items. so the expected output is like below,
const output = [
{
id: 1,
name: 'first',
type: 'first_type',
},
{
id: 2,
name: 'second',
type: 'second_type',
},
]
i have tried like below but that gives wrong output. its maybe filtering the input based on index.
const output = React.useMemo(
() => chosen_items.map(id => input[id]).filter(negate(isNil)),
[input, chosen_items]
);
with above code snippet i get output like below,
output = [
{
id: 2,
name: 'second',
type: 'second_type',
},
{
id: 3,
name: 'third',
type: 'third_type',
},
]
could someone help me fix this. how to filter input based on its id. thanks.
You can use filter() to do it,pay attention that in input,id is number,while in the chosen_items id is character.
const input = [
{
id: 1,
name: 'first',
type: 'first_type',
},
{
id: 2,
name: 'second',
type: 'second_type',
},
{
id: 3,
name: 'third',
type: 'third_type',
},
];
const chosen_items = ['1','2']
let result = input.filter(a => chosen_items.includes(a.id + ''))
console.log(result)

Create a new array of objects by property value from existing object add existing objects to new array

I have an existing array of objects which share a property titled type like so
[
{
id: 1,
name: 'a',
type: 'foo',
},{
id: 2,
name: 'b',
type: 'bar',
},{
id: 3,
name: 'c',
type: 'fizz',
},{
id: 4,
name: 'd',
type: 'foo',
},
]
I need to be able to structure a new array of objects with the existing ones grouped together by type like this
[
{
type: 'foo',
groups: [
{
id: 1,
name: 'a',
type: 'foo',
},{
id: 4,
name: 'd',
type: 'foo',
},
]
},{
type: 'bar',
groups: [
{
id: 2,
name: 'b',
type: 'bar',
}
]
},{
type: 'fizz',
groups: [
{
id: 3,
name: 'c',
type: 'fizz',
}
]
}
]
this is what I have so far but im not able to create the new array and organize the objects by type, only able to grab the type itself any help would be greatly appreciated!
Observable.value.map(objects => {
typesArr = [...new Set(objects.data.map(object => object.type))];
}); /// output = ['foo', 'bar', 'fizz']
Reduce the array to a Map, using the type as the key. Use Array.from() to convert the Map's values iterator to an array:
const arr = [{"id":1,"name":"a","type":"foo"},{"id":2,"name":"b","type":"bar"},{"id":3,"name":"c","type":"fizz"},{"id":4,"name":"d","type":"foo"}]
const result = Array.from(arr.reduce((acc, o) => {
const type = o.type
if(!acc.has(type)) acc.set(type, { type, groups: [] })
acc.get(type).groups.push(o)
return acc
}, new Map()).values())
console.log(result)
To make TS infer the type of the grouped array, infer the type of an item from the original array, and use it to set the type of the Map (TS playground):
const arr = [{"id":1,"name":"a","type":"foo"},{"id":2,"name":"b","type":"bar"},{"id":3,"name":"c","type":"fizz"},{"id":4,"name":"d","type":"foo"}]
type Item = (typeof arr)[0]
const result = Array.from(arr.reduce((acc, o) => {
const type = o.type
if(!acc.has(type)) acc.set(type, { type, groups: [] })
acc.get(type)!.groups.push(o)
return acc
}, new Map<string, { type: Item['type'], groups: Item[] }>()).values())
console.log(result)
Another option is to reduce the array to a map of groups [type, object], and then use Array.from() to convert the Map's entries to the required form (TS playground):
const arr = [{"id":1,"name":"a","type":"foo"},{"id":2,"name":"b","type":"bar"},{"id":3,"name":"c","type":"fizz"},{"id":4,"name":"d","type":"foo"}]
const result = Array.from(
arr.reduce((acc, o) => {
const type = o.type
if(!acc.has(type)) acc.set(type, [])
acc.get(type).push(o)
return acc
}, new Map()),
([type, groups]) => ({ type, groups })
)
console.log(result)

Javascript How to get all values for a property from an Array of Objects?

Hello fellow Javascript developers, I hope you're all having a good day.
I'm trying to get all dynamically set values for certain properties of object elements from an array for my filter. For e.g.
var data = [
{id: 0, category: "RINGS", type: "CH"},
{id: 1, category: "NECKLACE", type: "CHE"},
{id: 2, category: "PENDANT", type: "CH"},
{id: 3, category: "BRACELET", type: "CH"},
{id: 4, category: "RINGS", type: "HBR"},
{id: 5, category: "PENDANT", type: "CHE"},
];
and exmaple array for how my data comes from the api. As you can see the two properties category & type that I know will always remain constant but their values may change based on user input data.
I want to set all available values for these two object props for my filter. How do I get all the values for a certain prop to get myself an array of values for a certain property which then I can assign to my Dropdown in React Native.
Result:
var category = [
{ name: "Rings", id: "RINGS"},
{ name: "Necklace", id: "NECKLACE"},
{ name: "Pendant", id: "PENDANT"},
{ name: "Bracelet", id: "BRACELET"},
]
and
var type = [
{ name: "CH", id: "CH" },
{ name: "CHE", id: "CHE" },
{ name: "HBR", id: "HBR" },
]
and then these two arrays are basically passed to the filter which will then be used to sort the data. I assume it's not too complex, but I'm a total beginner in javascript so bear with me. Thank You.
var data = [
{ id: 0, category: 'RINGS', type: 'CH' },
{ id: 1, category: 'NECKLACE', type: 'CHE' },
{ id: 2, category: 'PENDANT', type: 'CH' },
{ id: 3, category: 'BRACELET', type: 'CH' },
{ id: 4, category: 'RINGS', type: 'HBR' },
{ id: 5, category: 'PENDANT', type: 'CHE' }
];
const categories = [], types = [];
data.forEach((item) => {
if (!categories.includes(item.category)) {
categories.push(item.category);
}
if (!types.includes(item.type)) {
types.push(item.type);
}
});
const category = categories.map((item) => ({
name: item.toLowerCase(),
id: item
}));
const type = types.map((item) => ({ name: item, id: item }));
console.log(category);
console.log(type);
There are atleast 2 ways you can do this:
Using Array.includes. As #baymax mentioned above, you can filter through the array using includes.
Using Set in Javascript. Check out the code.
const data = [
{id: 0, category: "RINGS", type: "CH"},
{id: 1, category: "NECKLACE", type: "CHE"},
{id: 2, category: "PENDANT", type: "CH"},
{id: 3, category: "BRACELET", type: "CH"},
{id: 4, category: "RINGS", type: "HBR"},
{id: 5, category: "PENDANT", type: "CHE"},
];
// by includes
const uniqueCategories = [];
const uniqueTypes = []
data.forEach(entry => {
if (!uniqueCategories.includes(entry.category)){
uniqueCategories.push(entry.category)
}
if (!uniqueTypes.includes(entry.type)){
uniqueTypes.push(entry.type)
}
})
const categoriesMap = uniqueCategories.map(category => ({name: category.toLowerCase(), id: category}));
const typesMap = uniqueTypes.map(typeEntry => ({name: typeEntry, id: typeEntry}));
// by set
const categoriesSet = new Set()
const typesSet = new Set()
data.forEach(entry => {
categoriesSet.add(entry.category);
typesSet.add(entry.type);
});
const uniqueCategoriesFromSet = Array.from(categoriesSet).map(category => ({name: category.toLowerCase(), id: category}));
const uniqueTypesFromSet = Array.from(typesSet).map(typeEntry => ({name: typeEntry, id: typeEntry}));
console.log(uniqueCategoriesFromSet, uniqueTypesFromSet);
console.log(categoriesMap, typesMap)

Flatten nested array with key value pairs in Javascript

Given an array like this:
[
{ id: 1, emailAddresses: ["bill#test.com", "bob#test.com"] },
{ id: 2, emailAddresses: ["sarah#test.com" },
{ id: 3, emailAddresses: ["jane#test.com", "laura#test.com", "paul#test.com"]
]
How could I use Javascript to reduce this to an array like this:
[
{ id: 1, emailAddress: "bill#test.com" },
{ id: 1, emailAddress: "bob#test.com" },
{ id: 2, emailAddress: "sarah#test.com" },
{ id: 3, emailAddress: "jane#test.com" },
{ id: 3, emailAddress: "laura#test.com" },
{ id: 3, emailAddress: "paul#test.com" }
]
I've read about the functions reduce, flat, map and so on and read lots of the questions on SO about using them but I can't find anything that's asking quite the same as this and I can't get my head around using those functions to do it.
You could use flatMap
const input = [
{ id: 1, emailAddresses: ["bill#test.com", "bob#test.com"] },
{ id: 2, emailAddresses: ["sarah#test.com"] },
{ id: 3, emailAddresses: ["jane#test.com", "laura#test.com", "paul#test.com"] }
]
const output = input.flatMap(o =>
o.emailAddresses.map(e => ({ id: o.id, emailAddress: e }) )
)
console.log(output)
If flatMap is not supported, you could use a nested for...of loop:
const input = [{id:1,emailAddresses:["bill#test.com","bob#test.com"]},{id:2,emailAddresses:["sarah#test.com"]},{id:3,emailAddresses:["jane#test.com","laura#test.com","paul#test.com"]}];
const output = []
for (const { id, emailAddresses } of input)
for (const emailAddress of emailAddresses)
output.push({ id, emailAddress })
console.log(output)
You can map over your data and then use reduce to flatten the resulting array:
const result = data
.map(datum => {
return datum.emailAddresses.map(emailAddress => {
return { id: datum.id, emailAddress };
});
})
.reduce((result, current) => {
return [...result, ...current];
}, []);
We can use Array.prototype.reduce to go over each object in the array and take into consideration the multiple values in the emailAddress property array and create separate object for each one and finally accumulate the new objects in the new array (r):
const data = [
{ id: 1, emailAddresses: ["bill#test.com", "bob#test.com"] },
{ id: 2, emailAddresses: ["sarah#test.com"] },
{ id: 3, emailAddresses: ["jane#test.com", "laura#test.com", "paul#test.com"]}
]
const flat = data.reduce((r, e) => {
e.emailAddresses.forEach((obj) => r.push({id: e.id, emailAddresses : obj }));
return r;
}, []);
console.log(flat);
You can use reduce and map
const data = [
{ id: 1, emailAddresses: ["bill#test.com", "bob#test.com"] },
{ id: 2, emailAddresses: ["sarah#test.com"] },
{ id: 3, emailAddresses: ["jane#test.com", "laura#test.com", "paul#test.com"]}
]
const flat = (toFlatten) =>
toFlatten.reduce((r,c)=> {
r.push(...c.emailAddresses.map(email=>({id: c.id, emailAddress: email})))
return r
}, [])
console.log(flat(data))
Here is a solution that doesn't use any array prototype but does, instead, take advantage of function generators.
The script below iterates the array, acquire all keys of the element except emailAddresses, which is handled separately, and for each email address it yields an object filled with the single email address and the rest of the data.
This solution iterate the original array only once.
Because it uses function generators, this solution is widely supported, it just won't work on IE due it's lack of support for function generators, despite babel or TSC can easily add compatibility to that.
const input = [
{ id: 1, emailAddresses: ["bill#test.com", "bob#test.com"] },
{ id: 2, emailAddresses: ["sarah#test.com"] },
{ id: 3, emailAddresses: ["jane#test.com", "laura#test.com", "paul#test.com"] }
];
function* flattenEmailAddresses(arr) {
for (var {emailAddresses, ...keys} of arr) {
for (var emailAddress of emailAddresses) yield {...keys, emailAddress};
}
}
console.log([...flattenEmailAddresses(input)]);

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