Destructuring array of objects in es6 - javascript

In es6, how can i simplify the following lines using destructuring?:
const array0 = someArray[0].data;
const array1 = someArray[1].data;
const array2 = someArray[2].data;

Whether using destructuring would actually be a simplification is debatable but this is how it can be done:
const [
{ data: array0 },
{ data: array1 },
{ data: array2 }
] = someArray
Live Example:
const someArray = [
{ data: 1 },
{ data: 2 },
{ data: 3 }
];
const [
{ data: array0 },
{ data: array1 },
{ data: array2 }
] = someArray
console.log(array0, array1, array2);
What is happening is that you're first extracting each object from someArray then destructuring each object by extracting the data property and renaming it:
// these 2 destructuring steps
const [ obj1, obj2, obj3 ] = someArray // step 1
const { data: array0 } = obj1 // step 2
const { data: array1 } = obj2 // step 2
const { data: array2 } = obj3 // step 2
// written together give
const [
{ data: array0 },
{ data: array1 },
{ data: array2 }
] = someArray
Maybe combine destructuring with mapping for (potentially) more readable code:
const [array0, array1, array2] = someArray.map(item => item.data)
Live Example:
const someArray = [
{ data: 1 },
{ data: 2 },
{ data: 3 }
];
const [array0, array1, array2] = someArray.map(item => item.data)
console.log(array0, array1, array2);

I believe what you actually want is
const array = someArray.map(x => x.data)
If you really want three variables (Hint: you shouldn't), you can combine that mapping with destructuring:
const [array0, array1, array2] = someArray.map(x => x.data)

If you want to do with this pure JS then follow this code snippet. It will help you.
let myArray = [
{
"_id": "1",
"subdata": [
{
"subid": "11",
"name": "A"
},
{
"subid": "12",
"name": "B"
}
]
},
{
"_id": "2",
"subdata": [
{
"subid": "12",
"name": "B"
},
{
"subid": "33",
"name": "E"
}
]
}
]
const array = myArray.map(x => x.subdata).flat(1)
const isExist = (key,value, a) => {
return a.find(item => item[key] == value)
}
let a = array.reduce((acc, curr) => {
if(!isExist('subid', curr.subid, acc)) {
acc.push(curr)
}
return acc
}, [])
console.log(a)

const myInfo = someArray.map((item) => {
const {itemval1, itemval2} = item;
return(
//return data how you want it eg:
<p>{itemval1}</p>
<p>{itemval2}</p>)
})
This is how I did it in react, correct me if m wrong, I'm still new to this world

#Daniel, I presume you were looking to destructure a nested Object in an array of Objects. Following #nem035 was able to extract the nested Object's property using his pattern.
What is happening is that you're first extracting each object from addresses array then destructuring each object by extracting its properties and renaming it including the nested Object:
addresses = [
{
locality:"Sarjapura, Bangalore",
coordinates:{latitude:"12.901160", longitude:"77.711680"}
},
{
locality:"Vadakara, Kozhikode",
coordinates:{latitude:"11.588980", longitude:"75.596450"}
}
]
const [
{locality:loc1, coordinates:{latitude:lat1, longitude:ltd1}},
{locality:loc2, coordinates:{latitude:lat2, longitude:ltd2}}
] = addresses
console.log(`Latitude of Vadakara :: ${lat2}`)

Related

Create an array of objects based on an object if one or more properties have multiple values differentiated by a comma

i'm trying to duplicate objects based on two properties that have multiple values differentiated by a comma.
For example:
I have an object
const obj = {
id: 1
date: "2021"
tst1: "111, 222"
tst2: "AAA, BBB"
}
And I would like the result to be an array of 2 objects in this case (because there are 2 values in tst1 OR tst2, these 2 properties will always have the same nr of values differentiated by a comma)
[{
id: 1,
date: "2021",
tst1: "111",
tst2: "AAA",
},
{
id: 1,
date: "2021",
tst1: "222",
tst2: "BBB",
}]
What I tried is this:
I created a temporary object
const tempObject = {
id: obj.id,
date: obj.date,
}
And then I would split and map the property that has multiple values, like this:
cont newObj = obj.tst1.split(",").map(function(value) {
let finalObj = {}
return finalObj = {
id: tempObject.id,
date: tempObject.date,
tst1: value,
})
And now, the newObj is an array of objects and each object contains a value of tst1.
The problem is I still have to do the same for the tst2...
And I was wondering if there is a simpler method to do this...
Thank you!
Here is an example that accepts an array of duplicate keys to differentiate. It first maps them to arrays of entries by splitting on ',' and then trimming the entries, then zips them by index to create sub-arrays of each specified property, finally it returns a result of the original object spread against an Object.fromEntries of the zipped properties.
const mapDuplicateProps = (obj, props) => {
const splitProps = props.map((p) =>
obj[p].split(',').map((s) => [p, s.trim()])
);
// [ [[ 'tst1', '111' ], [ 'tst1', '222' ]], [[ 'tst2', 'AAA' ], [ 'tst2', 'BBB' ]] ]
const dupeEntries = splitProps[0].map((_, i) => splitProps.map((p) => p[i]));
// [ [[ 'tst1', '111' ], [ 'tst2', 'AAA' ]], [[ 'tst1', '222' ], [ 'tst2', 'BBB' ]] ]
return dupeEntries.map((d) => ({ ...obj, ...Object.fromEntries(d) }));
};
const obj = {
id: 1,
date: '2021',
tst1: '111, 222',
tst2: 'AAA, BBB',
};
console.log(mapDuplicateProps(obj, ['tst1', 'tst2']));
Not sure if that's what you're searching for, but I tried making a more general use of what you try to do:
const duplicateProperties = obj => {
const properties = Object.entries(obj);
let acc = [{}];
properties.forEach(([key, value]) => {
if (typeof value === 'string' && value.includes(',')) {
const values = value.split(',');
values.forEach((v, i) => {
if (!acc[i]) {
acc[i] = {};
}
acc[i][key] = v.trim();
});
} else {
acc.forEach(o => o[key] = value);
}
});
return acc;
};
const obj = {
id: 1,
date: '2021',
tst1: '111, 222',
tst2: 'AAA, BBB',
};
console.log(duplicateProperties(obj));
You could start by determining the length of the result using Math.max(), String.split() etc.
Then you'd create an Array using Array.from(), returning the correct object for each value of the output index.
const obj = {
id: 1,
date: "2021",
tst1: "111, 222",
tst2: "AAA, BBB",
}
// Determine the length of our output array...
const length = Math.max(...Object.values(obj).map(s => (s + '').split(',').length))
// Map the object using the relevant index...
const result = Array.from({ length }, (_, idx) => {
return Object.fromEntries(Object.entries(obj).map(([key, value]) => {
const a = (value + '').split(/,\s*/);
return [key, a.length > 1 ? a[idx] : value ]
}))
})
console.log(result)
.as-console-wrapper { max-height: 100% !important; }

Create a single array of strings out of an array of objects with arrays of strings within those objects

As the title suggests, I am trying to create a single array of strings:
['string1', 'string2', 'string3', 'string4', 'string5', 'string6']
Out of an array of objects with arrays of strings within those objects:
[
{
array_of_strings: ['string1', 'string2', 'string3']
},
{
array_of_strings: ['string1', 'string4', 'string5']
},
{
array_of_strings: ['string6', 'string3', 'string2']
}
]
As you can see there is a possibility that the nested arrays may contain the same strings as each other, and I am trying to de-duplicate at the same time. I got very lost in map, filter and reduce. But nothing really outputs the data as needed.
Any guidance would be appreciated.
You need none of map/filter/reduce :-) Use flatMap, then deduplicate:
const data = [
{
array_of_strings: ['string1', 'string2', 'string3']
},
{
array_of_strings: ['string1', 'string4', 'string5']
},
{
array_of_strings: ['string6', 'string3', 'string2']
}
];
const result = Array.from(new Set(data.flatMap(o => o.array_of_strings)));
console.log(result);
You can use a javascript Set for this, check the docs
const array = [
{
array_of_strings: ["string1", "string2", "string3"],
},
{
array_of_strings: ["string1", "string4", "string5"],
},
{
array_of_strings: ["string6", "string3", "string2"],
},
];
const result = array.reduce((acc, { array_of_strings }) => {
return acc.concat(array_of_strings);
}, []);
const unique = new Set(result);
const uniqueArray = Array.from(unique);
console.log(uniqueArray);
First you want to "regroup" all of thoses strings together in the same array :
const fullDatas = [
{
array_of_strings: ["string1", "string2", "string3"],
},
{
array_of_strings: ["string1", "string4", "string5"],
},
{
array_of_strings: ["string6", "string3", "string2"],
},
];
const allStrings = fullDatas.reduce((acc, currentValue)) => {
return acc.concat(currentValue.array_of_strings);
}, []);
then you can have a look at this thread
and use it :
const uniq = [...new Set(allStrings)];
If I understand your question correctly(to get all the elements appear more than once),we can use Array.filter() ,Array.reduce(), Array.map() to do it
let data = [
{
array_of_strings: ['string1', 'string2', 'string3']
},
{
array_of_strings: ['string1', 'string4', 'string5']
},
{
array_of_strings: ['string6', 'string3', 'string2']
}
]
data = data.map(d => d.array_of_strings).flat().reduce((a,v) =>{
a[v] = a[v]??0
a[v] += 1
return a
},{})
let result = Object.entries(data).filter(i => i[1] > 1).map(i => i[0])
console.log(result)

re-organizing array of objects

So I have an array of objects that contain information for different activities in different projects.
It looks something like this
const input = [
{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
From this, I would like to go to this
output = [{
Project: 1,
ID1: 1 - 1,
ID2: 1 - 2,
},
{
Project: 1,
ID1: 2 - 1,
},
];
Here's what I have so far:
let currentProject = ''
let output = []
for (const e of input) {
let counter
let outputObj = {}
if (currentProject !== e.Project) {
output.push(outputObj)
counter = 1
outputObj = {}
outputObj.projectNum = e.Project
currentProject = e.Project
}
if (currentProject == e.Project) {
outputObj['ID' + counter] = e.ID
counter++
}
}
here's what I'm getting back:
output = [{
Project: 1,
ID1: 1 - 1
},
{
Project: 1,
ID1: 2 - 1
}
]
I'm not sure what the issue is, tried several times to fix it.
Could someone please help me get over the edge?
Any help will be greatly appreciated.
You can achieve this using reduce, Object.keys
const input = [{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
const result = input.reduce((acc, curr) => {
const { Project, ID } = curr;
const obj = acc.find((el) => el.Project === Project);
if (obj) {
const length = Object.keys(obj).length;
obj[`ID${length}`] = ID;
} else {
acc.push({ Project, [`ID${1}`]: ID });
}
return acc;
}, []);
console.log(result);
You can try this.
const input=[{Project:1,ID:"1-1",},{Project:1,ID:"1-2",},{Project:2,ID:"2-1"}];
let temp = {};
input.map(v=>(temp[v.Project] ??= []).push(v.ID));
let output = Object.keys(temp).map(k=>{
let json = {Project:k};
temp[k].map((v,k)=>json['ID'+(Number(k+1))]=v);
return json;
});
console.log(output);
you will get the result.
[
{ Project: '1', ID1: '1-1', ID2: '1-2' },
{ Project: '2', ID1: '2-1' }
]
The way you intended to implement this assumes every project from same id comes sequentially grouped.
While #decpk answer deals with with a linear search, for performance reasons I would rather first use a dictionary and then convert to an array, AND also keep track of id quantities using a field n.
const input = [
{
Project: 1,
ID: "1-1",
},
{
Project: 1,
ID: "1-2",
},
{
Project: 2,
ID: "2-1",
},
];
const projects = {}
for (const e of input) {
let pid = e.Project
let project = projects[pid]
//First time seeing this project
if (!project) {
projects[pid] = { Project: pid, n: 1, ID1: e.ID }
}
//insert more ID
else {
project.n += 1
project[`ID${project.n}`] = e.ID
}
}
//And now converting the object to array, removing the 'n' field
const output = Object.keys(projects).map(pid => {
const obj = projects[pid]
delete obj.n
obj.Project = pid
return obj
})
You can try this way - O(n) time complexity
Using reduce to aggregate data.
Using logical nullish assignment only assigns if acc[Project] is nullish (null or undefined).
Define each additional key-value pair like:
const number = Object.keys(acc[Project]).length; // Define key format by number of existing property.
const key = `ID${number}`;
instead of using count variable.
const input=[{Project:1,ID:"1-1",},{Project:1,ID:"1-2",},{Project:2,ID:"2-1",}];
const output = input.reduce((acc, {Project, ID}) =>
{
acc[Project] ??= {Project}; // Get exist object or create new one
const number = Object.keys(acc[Project]).length; // Define key format by number of existing property.
const key = `ID${number}`;
acc[Project][key] = ID;
return acc;
}, {});
console.log(Object.values(output));
Output:
[
{
"Project": 1,
"ID1": "1-1",
"ID2": "1-2"
},
{
"Project": 2,
"ID1": "2-1"
}
]

Trying to 'map' nested JSON element object (javascript)

I am trying to 'map' nested JSON elements that have objects in order to build HTML. I am not sure what I am doing wrong with the syntax as follows:
array1 = [
{
"name":"test",
"things": [
{ "name":"thing1" },
{ "name": "thing2"}
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`
// pass a function to map
const map1 = array1.things.map(createThingy).join('');
console.log(array1);
// expected output: <p>thing1</p><p>thing2</p>
Thank you in advance for your time and consideration.
Think of the array as an object. It's accessed in a similar way, so if it were an object it would be like this:
let array1 = {
0: {
"name":"test",
"things": [
{ "name": "thing1" },
{ "name": "thing2" }
]
}
};
Therefore, to access its first element directly you need:
array1[0].things
To get your desired outcome you need to the following:
let array1 = [
{
"name": "test",
"things": [
{ "name": "thing1" },
{ "name": "thing2" }
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`;
// pass a function to map
const map1 = array1[0].things.map(createThingy).join('');
console.log(map1);
In case your array can have multiple elements, you can use the following:
let array1 = [
{
"name": "test",
"things": [
{ "name": "thing1" },
{ "name": "thing2" }
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`;
// pass a function to map
const map1 = array1.reduce((acc, elem) => acc + elem.things.map(createThingy).join(''), "");
console.log(map1);
array1 = [
{
"name":"test",
"things": [
{ "name":"thing1" },
{ "name": "thing2"}
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`
// pass a function to map
const map1 = array1[0].things.map(createThingy).join('');
console.log(array1);
console.log(map1);
As Nick Parsons said, you have to loop over the array1 array to get things property.
const array1 = [
{
"name":"test",
"things": [
{ "name":"thing1" },
{ "name": "thing2"}
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`
// pass a function to map
const map1 = array1[0].things.map(createThingy).join('');
console.log(array1);
console.log(map1);
Also, be advised that if your array1 variable is empty or in case there is no things attribute in preferred index, your code code will give error. Be sure to check if they are empty. You can do this by using lodash isEmpty function.
You have to loop over the array1 to get the desired output as Nick Parsons said in the comments.
array1 = [
{
"name":"test",
"things": [
{ "name":"thing1" },
{ "name": "thing2"}
]
}
];
const createThingy = (item) => `
<p>${item.name}</p>
`
array1.map(item => {
item.map(key => createThingy(key).join(''));
});
// expected output: <p>thing1</p><p>thing2</p>

Javascript: Split array of objects into seperate arrays with dynamic names depending on property value

I have an array containing objects. Now I want to slice the array to new arrays containing only those objects matching a certain property value.
Ideally the new array names should be created dynamically.
The original array looks like this:
specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
The new arrays should look like this:
timespan1 = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1}
]
timespan2 = [
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2}
]
timespan3 = [
{slotStarttime:"18:00:00", slotTimespan:3}
]
If possible, I want to avoid javascript syntax / functions, which are not supported by IE and some other older browsers.
I already tried to work with reduce() and slice(), but did not find a solution.
You can simply achieve your desired outcome using reduce, as you can produce an object using reduce, here's an example of how you could do it.
As you can see, it'll check that the relevant property on the object isn't null, if it is, then it's set to an empty array, after this check, it's safe to simply push the relevant values onto the array, like so.
var array = [{
slotStarttime: "06:00:00",
slotTimespan: 1
},
{
slotStarttime: "09:00:00",
slotTimespan: 1
},
{
slotStarttime: "12:00:00",
slotTimespan: 2
},
{
slotStarttime: "15:00:00",
slotTimespan: 2
},
{
slotStarttime: "18:00:00",
slotTimespan: 3
}
];
var newObject = array.reduce(function(obj, value) {
var key = `timespan${value.slotTimespan}`;
if (obj[key] == null) obj[key] = [];
obj[key].push(value);
return obj;
}, {});
console.log(newObject);
Use a generic group by key reducer. I will take it from a previous answer of mine. It is an elegant and simple way to generate a function that group your data by a particular key that comes as an argument.
const groupBy = key => (result,current) => {
const item = Object.assign({},current);
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
const timespan = specificSlotButtonArray.reduce(groupBy('slotTimespan'),{});
console.log(timespan);
You could reduce the array by taking an object for the part arrays.
var specificSlotButtonArray = [{ slotStarttime: "06:00:00", slotTimespan: 1 }, { slotStarttime: "09:00:00", slotTimespan: 1 }, { slotStarttime: "12:00:00", slotTimespan: 2 }, { slotStarttime: "15:00:00", slotTimespan: 2 }, { slotStarttime: "18:00:00", slotTimespan: 3 }],
timespan1 = [],
timespan2 = [],
timespan3 = [];
specificSlotButtonArray.reduce(function (r, o) {
r[o.slotTimespan].push(o);
return r;
}, { 1: timespan1, 2: timespan2, 3: timespan3 });
console.log(timespan1);
console.log(timespan2);
console.log(timespan3);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The following soluce iterates once on specificSlotButtonArray using Array.reduce. This soluce will adapt to any number of slotTimespan.
const specificSlotButtonArray = [{
slotStarttime: '06:00:00',
slotTimespan: 1,
},
{
slotStarttime: '09:00:00',
slotTimespan: 1,
},
{
slotStarttime: '12:00:00',
slotTimespan: 2,
},
{
slotStarttime: '15:00:00',
slotTimespan: 2,
},
{
slotStarttime: '18:00:00',
slotTimespan: 3,
},
];
// Loop through the array
const splitted = specificSlotButtonArray.reduce((tmp, x) => {
// Look if we got already an array having the slotTimespan of the current
// item to treat
const match = tmp.find(y => y.some(z => z.slotTimespan === x.slotTimespan));
// If we have such array, push the data into it
if (match) {
match.push(x);
} else {
// If we don't create a new array
tmp.push([x]);
}
return tmp;
}, []);
console.log(splitted);
If you want to deals with the array straight after the Array.reduce you can use destructuration :
const [
timespan1,
timespan2,
timespan3
] = specificSlotButtonArray.reduce((tmp, x) => {
You can use this function to create separate arrays grouped by slotTimespan,
specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
function groupBy(arr, property) {
return arr.reduce(function(memo, x) {
if (!memo[x[property]]) { memo[x[property]] = []; }
memo[x[property]].push(x);
return memo;
}, {});
}
console.log(groupBy(specificSlotButtonArray, "slotTimespan"));

Categories