Descontruct array of objects to get nested values ES6 - javascript

I have an array of objects like:
const array = [
{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false},
]
},
{
name: 'object2',
value: false,
}
];
I need to get value of each object in array.
To get object1 and object2 values I have used
const [{value: object1}, {value: object2}] = array;
How can I get values of objects which are in parameters array? How to deconstruct it in right way? Cannot find the right way..

You'd have to use parameters: and keep destructuring:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const [{ parameters: [
{ value: value1 },
{ value: value2 }
]}] = array;
console.log(value1, value2);
But that's not remotely readable IMO. I'd prefer to use standard dot/bracket notation to get to the parameters array, and .map to extract the values:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const values = array[0].parameters.map(({ value }) => value);
console.log(values);

You could take Array#flatMap and map the values of paramters only.
const
array = [{ name: 'object1', value: true, parameters: [{ name: 'inner1', value: true }, { name: 'inner2', value: false }] }, { name: 'object2', value: false }],
values = array.flatMap(({ parameters = []}) => parameters.map(({ value }) => value));
console.log(values);

The deconstruction must follow the shape of the object it is deconstructing. A good way to think of it in situations like this, is to just copy the object itself, and then replace each value with a variable name to assign that value to
// Object from which to deconstruct values
const myArray = [{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false}]
}];
// Deconstruction
const [{
name: nameVar,
value: valueVar,
parameters: [
{ name: paramNameVar1, value: valueVar1},
{ name: paramNameVar2, value: valueVar2}]
}] = myArray
Of course once you start getting more complex objects, it is possably more effort, less readable, and less efficient to deconstruct this way.

Related

JavaScript - update deeply nested array of objects with the target path

The nesting level is always unknown, and children can be either undefined or an array with at least one item. Each key is always unique. This would be an example:
const arr = [{
key: '001',
children: [{
key: 'abc',
children: [{
key: 'ee',
children: [{
key: 'goc',
}, {
key: 'zzv',
children: [{
key: '241',
}],
}],
}],
}, {
key: '125',
children: undefined,
}],
}, {
key: '003',
children: [{
key: 'ahge',
}, {
key: '21521',
}],
}];
I'd like to write a function that receives a key to find the element and then updates its children field with the given children array and then returns the whole arr.
// Function that returns arr with updated the target element - how can I write this?
const mysteryFn = (arr, key, childrenToUpdate) => {
// Do something..
return arr;
}
const key = 'goc';
const childrenToUpdate = [{
key: '12345',
}, {
key: '25221a',
}];
const newArr = mysteryFn(arr, key, childrenToUpdate);
// expected newArr
const newArr= [{
key: '001',
children: [{
key: 'abc',
children: [{
key: 'ee',
children: [{
key: 'goc',
children: [{
key: '12345',
}, {
key: '25221a',
}],
}, {
key: 'zzv',
children: [{
key: '241',
}],
}],
}],
}, {
key: '125',
children: undefined,
}],
}, {
key: '003',
children: [{
key: 'ahge',
}, {
key: '21521',
}],
}];
This can be achieved with recursion.
const mysteryFn = (arr, key, childrenToUpdate) => {
// if children are undefined
if (!arr) return;
// loop over each entry and its children to find
// entry with passed key
arr.forEach((entry) => {
if (entry.key === key) {
entry.children = childrenToUpdate;
}
// recursive call to traverse children
mysteryFn(entry.children, key, childrenToUpdate);
});
return arr;
};

Filtering array from object nested in array react

I have an array of object which objects have array, and my problem is to filter objects based on values from a nested array.
const skus = [{
id: 1,
features: ["Slim"],
fields: [{
label: "Material",
value: "Material1"
}, ]
},
{
id: 2,
features: ["Cotton"],
fields: [{
label: "Material",
value: "Material2"
}, ]
},
{
id: 3,
features: ["Slim"],
fields: [{
label: "Material",
value: "Material3"
}, ]
}
];
output should be array based on features array, example:
const result = [{
id: 2,
features: ["Cotton"],
fields: [{
label: "Material",
value: "Material2"
},
{
label: "Type",
value: "Type2"
}
]
}]
I tried to using filter method, but it only works on on objects, but not on arrays nested in objects
const filteredData = skus.filter((item) =>
(item.fields.filter((field) => field.value === "Material2")).length !== 0
);
console.log(filteredData);
I think this is what you meant...
Well to understand better you must understand that Array is also a special object only in javascript so you can perform filter on objects or the nested objects too.
skus.filter((item,keys)=>{
return item['features'].includes("Cotton") // Pass the search term in includes
})
With this you can achieve your goal.
Let me know if this works for you.
I got the same output of the example you gave using :
skus.filter(sku => sku.features.includes("Cotton"));
I hope you can explain a bit more.
The Filter method allows you to delve deeper into an objects properties and perform comparisons.
const skus = [
{ id: 1, features: ["Slim"], fields: [{ label: "Material", value: "Material1" },] },
{ id: 2, features: ["Cotton"], fields: [{ label: "Material", value: "Material2" },] },
{ id: 3, features: ["Slim"], fields: [{ label: "Material", value: "Material3" },] }
];
let featureName = "Cotton"
let results = skus.filter(s => s.features.includes(featureName))
console.log(results);
I'm unsure where "{ label: "Type", value: "Type2" }" suddenly comes from in your results though?
I write this code, and got same output,
I using id and value from index features
const skus = [
{
id: 1,
features: ['Slim'],
fields: [
{
label: 'Material',
value: 'Material1'
}
]
},
{
id: 2,
features: ['Cotton'],
fields: [
{
label: 'Material',
value: 'Material2'
}
]
},
{
id: 3,
features: ['Slim'],
fields: [
{
label: 'Material',
value: 'Material3'
}
]
}
]
const result = skus.filter(
(item) => item.id === 2 && item.features[0] === 'Cotton'
)
console.log(result)

ReactJs | Array of Arrays deconstruction problem

Situation is simple: Make a double map to deconstruct into a single Array rather then multiple.
The Data example:
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
A method should take this array and convert into a single array of this data (order dosent matter):
const proccessedData = [
{ index: '1993', value: 5, name: 'testa' },
{ index: '1994', value: 6, name: 'testa' },
{ index: '1991', value: 8, name: 'testb' },
{ index: '1992', value: 3, name: 'testb' },
{ index: '1993', value: 9, name: 'testb' },
];
I achieve this by using this method I created:
const getData = (obj) => {
const data = [];
obj.map(({ values, name }) => {
data.push(...values.map(({ index, value }) => ({ index, value, name })));
});
return data;
};
And it works BUT I disliake it because of (read below in The Problem):
THE PROBLEM
It depends on const data = [] to do a data.push(...). Would prefer that it would auto decontruct it so a method would look something like this:
const getData = (obj) =>
obj.map(({ values, name }) => values.map(({ index, value }) => ({ index, value, name })));
Basically, on a single line, without the use of another variable BUT the return structure would remain as mentioned above. But using thtis method it returns an array with 2 different arrays inside.
It is being used inside another structure like so:
const config = {
data: getData(data),
height: 400,
xField: "index",
yField: "value",
seriesField: "name"
};
So it has to return deconstructed array already without involving any other variables. Yes, I could leave it as it is right now, but I wanna do the deconstruction way as its cleaner, in my opinion, and I would learn something new.
NOTE doing data: {...getData(data)}, or data: [...getData(data)], does Not work.
A working example to play around: https://codesandbox.io/s/bold-cannon-fwot6?file=/src/App.js:690-826
This would be simpler with flatMap:
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
proccessedData = data.flatMap(d => d.values.map(v => ({...v, name: d.name})))
console.log(proccessedData)
You can also try this: I am using here map function twice, and then flatten into a single array, The flatMap method is identical to a map followed by a call to a flat of depth 1.
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
const dataProcess = data
.map((d) =>
d.values.map((v) => ({...v, name: d.name}))
).flat();
console.log(dataProcess);

Keep all the keys of the object after removing duplicates from a slightly nested array

I have the same issue of this question but my objects have more keys for example:
[{
id: 1
name: "abcd",
value: 123,
type: "foo"
},
{
id: 1
name: "abcd",
value: 321,
type: "faa"
},
{
id: 2
name: "dcba",
value: 456,
type: "baa"
}]
I want to achieve something like this:
[{
id: 1,
name: "abcd",
value: [123, 321],
type: ["foo", "faa"]
},
{
id: 2
name: "dcba",
value: [456],
type: ["baa"]
}]
The extra keys have the same value.
The idea is to group by the id, then map each group of objects, pick the id and name from the 1st object, extract all value and type from all objects in the group, transpose, and zip to an another object, and merge them.
const { pipe, groupBy, prop, values, map, converge, merge, head, pick, props, transpose, zipObj } = R
const fn = pipe(
groupBy(prop('id')), // groupBy the id
values, // convert the object of groups to array of groups
map(converge(merge, [ // map each group by merging the results of...
pipe(head, pick(['id', 'name'])), // getting the id and name from the 1st item
pipe(map(props(['value', 'type'])), transpose, zipObj(['value', 'type'])) // extract the value and type and zipping to an object
]))
)
const data = [{
id: 1,
name: "abcd",
value: 123,
type: "foo"
},
{
id: 1,
name: "abcd",
value: 321,
type: "faa"
},
{
id: 2,
name: "dcba",
value: 456,
type: "baa"
}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
You can grab the distinct id , loop over them and group them using filter and map
let data = [{
id: 1,
name: "abcd",
value: 123,
type: "foo"
},
{
id: 1,
name: "abcd",
value: 321,
type: "faa"
},
{
id: 2,
name: "dcba",
value: 456,
type: "baa"
}];
//grab unique
let distinct = [...new Set(data.map(a => a.id))];
let grouped = distinct.map(d => {
let filtered=data.filter(d1 => d1.id === d);
return {
id: d,
name: filtered.map(d2 => d2.name)[0],
value: [...new Set(filtered.map(d2 => d2.value))],
type: [...new Set(filtered.map(d2 => d2.type))]
}
});
console.log(grouped);

Clone array of object removes class type

I have to deep clone an array of objects
filterList: Filter[] = [
new ChipsFilter('Rating', 'rating',
[
{
name: '5 ★',
key: '5',
value: true
},
{
name: '4 ★',
key: '4',
value: true
},
{
name: '3 ★',
key: '3',
value: true
},
{
name: '2 ★',
key: '2',
value: true
},
{
name: '1 ★',
key: '1',
value: true
}
]),
new CheckboxFilter('Country', 'country', [
{
name: 'India',
key: 'india',
value: true
},
{
name: 'Brazil',
key: 'brazil',
value: false
},
{
name: 'UAE',
key: 'uae',
value: true
},
{
name: 'Sri Lanka',
key: 'sri-lanka',
value: true
},
{
name: 'USA',
key: 'usa',
value: false
},
{
name: 'England',
key: 'england',
value: true
},
{
name: 'South Africa',
key: 'south-africa',
value: true
}
]),
new CalendarFilter('Date', 'createdAt', [
{
name: 'Start Date',
key: 'startDate',
value: ''
},
{
name: 'End Date',
key: 'endDate',
value: ''
}
]),
];
After clone I want the data type of objects to be same but I get the object as the type instead, have tried below methods for cloning.
Using JSON stringify
this.filterList = this.filterList.map(a => Object.assign({}, a));
Using object.assign
this.filterList = this.filterList.map(a => Object.assign({}, a));
The first argument to Object.assign() is the target object. That object effectively is the result. What Object.assign() does is just copy over own enumerable properties of your CalendarFilter instances to that target.
What you could do instead is create new instances of your objects in array.map() instead of assigning them to a generic object with Object.assign().
this.filterList = this.filterList.map(a => new CalendarFilter(...))
Of course, you need to use the right constructor for each type you encounter in your array.
This will take into account the variable Object types:
class ChipsFilter {constructor(){this.chipsProp="chipsProp"}}
class CheckboxFilter {constructor(){this.checkboxProp= "checkboxProp"}}
class CalendarFilter {constructor(){this.calendarProp= "calendarProp"}}
const filterList = [
new ChipsFilter(),
new CheckboxFilter(),
new CalendarFilter(),
];
let out = filterList.map(obj=>Object.assign(new obj.constructor, obj));
console.log(out[0].constructor, out[0]);
console.log(out[1].constructor, out[1]);
console.log(out[2].constructor, out[2]);

Categories