Suppose there is an array like this:
const a = [ {p:1}, {p:2}, {p:3} ];
Is it possible to destructure this array in order to obtain p = [1, 2, 3] ?
Because this does not work :
const [ ...{ p } ] = a; // no error, same as const p = a.p;
// p = undefined;
Edit
In response to all the answers saying that I need to use Array.prototype.map, I am aware of this. I was simply wondering if there was a way to map during the destructuring process, and the answer is : no, I need to destructure the array itself, then use map as a separate step.
For example:
const data = {
id: 123,
name: 'John',
attributes: [{ id:300, label:'attrA' }, { id:301, label:'attrB' }]
};
function format(data) {
const { id, name, attributes } = data;
const attr = attributes.map(({ label }) => label);
return { id, name, attr };
}
console.log( format(data) };
// { id:123, name:'John', attr:['attrA', 'attrB'] }
I was simply wondering if there was a way, directly during destructuring, without using map (and, respectfully, without the bloated lodash library), to retrive all label properties into an array of strings.
Honestly I think that what you are looking for doesn't exist, normally you would map the array to create a new array using values from properties. In this specific case it would be like this
const p = a.map(element => element.p)
Of course, there are some packages that have many utilities to help, like Lodash's map function with the 'property' iteratee
you can destructure the first item like this :
const [{ p }] = a;
but for getting all values you need to use .map
and the simplest way might be this :
const val = a.map(({p}) => p)
Here's a generalized solution that groups all properties into arrays, letting you destructure any property:
const group = (array) => array.reduce((acc,obj) => {
for(let [key,val] of Object.entries(obj)){
acc[key] ||= [];
acc[key].push(val)
}
return acc
}, {})
const ar = [ {p:1}, {p:2}, {p:3} ];
const {p} = group(ar)
console.log(p)
const ar2 = [{a:2,b:1},{a:5,b:4}, {c:1}]
const {a,b,c} = group(ar2)
console.log(a,b,c)
I have an array of objects that looks like below
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
I am trying to loop through the array and return an array of items group by the key "name" which will hold indexes of the items with same key.
expected result like below:
[
{bene: [0,2]},
{leg: [1,3]},
{hello: [4]}
]
I've put together the below but can't get it to work.
var obj = FinalArray.reduce(function(agg, item, index, f) {
var name = item.name || ""
var index = FinalArray.findIndex(item)
/* var copy = [...item.jArray];
*/ if (!agg[name]) {
agg[name] = []
}
agg[name].push(index)
return agg;
}, {})
fairly new to using reduce and groupby. any help is appreciated. Thanks
You can generate an object of the names with their indexes with a reduce on the original array, just pushing indexes into the array for each name.
If you then want an array of those values (I'm not sure this is a better structure), you can use Object.entries to get the key value pairs and map those into individual objects in an array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
var obj = FinalArray.reduce((acc, { name }, i) => {
acc[name] = (acc[name] || []).concat([i])
return acc
}, {})
console.log(obj)
objArray = Object.entries(obj).map(([k, v]) => ({ [k] : v }))
console.log(objArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can achieve this by just using two JavaScript methods Array.forEach() along with Object.keys().
Live Demo :
// Input array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}
];
const resObj = {};
const output = [];
// creating a object with the required key: values.
FinalArray.forEach((obj, index) => {
resObj[obj.name] ? resObj[obj.name].push(index) : resObj[obj.name] = [index];
});
// destructuring the object into an array of objects.
Object.keys(resObj).forEach(key => {
output.push({
[key]: resObj[key]
})
});
// final output
console.log(output);
The OP might try a combination of ...
a reduce based approach which straightforwardly creates and collects an index/map of name based groups where the group key resemble an iterated item's name key, and the group value is an array of same name-value item-indices.
and a mapping of the reduced object's entries.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
console.log(
'index/map based result ...',
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
);
console.log(
"OP's expected result ...",
Object
.entries(
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
)
.map(([key, value]) => ({ [ key ]: value }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another approach was to solely stick to reduce, where one then needs to implement a reducer function which achieves everything in a single run and does both ...
keeping track of the (to be) generated groups and the (to be) collected indices
and aggregating the final result of the reduce method's accumulator/collector object which gets passed as the method's 2nd parameter ... its initialValue.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
const { result } = finalArray
.reduce(({ result = [], groups = {} }, { name }, idx) => {
let group = groups[name];
if (!group) {
group = groups[name] = { [ name ]: [] };
result.push(group);
}
group[name].push(idx)
return { result, groups };
}, { result: [] });
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }
I have the following structure:
let mappings = {
"1002": ["1000", "1003"],
"2000": ["2001", "2002"]
}
and I want to add this piece of data
const issueTypes = ["4000"]
to each of the arrays of the object keys ending with this
mappings = {
"1002": ["1000", "1003", "4000"],
"2000": ["2001", "2002", "4000"]
}
This is what I have so far:
mappings = Object.keys(mappings).reduce((prev, curr, index) => {
console.log("prevous", prev)
console.log("curret", curr)
return ({
...prev, [curr]: //unsure of this part which is kind of crucial
})}, mappings)
Any help would be really appreciated
Why not just iterate over the values of the object, and push?
const mappings = {
"1002": ["1000", "1003"],
"2000": ["2001", "2002"]
}
const issueTypes = ["4000"]
for (const arr of Object.values(mappings)) {
arr.push(...issueTypes);
}
console.log(mappings);
If it must be done immutably, map the entries of the object to a new array of entries, while spreading the new issueTypes into the value.
const mappings = {
"1002": ["1000", "1003"],
"2000": ["2001", "2002"]
}
const issueTypes = ["4000"]
const newMappings = Object.fromEntries(
Object.entries(mappings).map(
([key, arr]) => [key, [...arr, ...issueTypes]]
)
);
console.log(newMappings);
The procedure is quite simple. What you need to do is this —
Iterate over each value of the mappings object.
Push the new value
Refer to the following code and adapt —
let mappings = {
"1002": ["1000", "1003"],
"2000": ["2001", "2002"]
}
const issueTypes = ["4000"]
for (const item in mappings) {
mappings[item].push(issueTypes[0])
}
Hope this helps! :)
I have an object like this
{
metadata: {
correlationId: 'b24e9f21-6977-4553-abc7-416f8ed2da2d',
createdDateTime: '2021-06-15T16:46:24.247Z'
}
}
and I have an array of the properties I wanna access
[metadata, correlationId]
how can I dynamically access the property on the object?
like
keys.forEach((key) => {
object[key][key2] ???
})
it needs to be dynamic since I don't know how deep we need to access the object
Here is a solution without recursion:
const myObj = {
a: {
b: {
c: "I'm the target"
}
}
}
const keys = ['a', 'b', 'c'];
let result = myObj;
for (const key of keys) {
result = result[key];
}
console.log(result);
Or with recursion:
const finder = (obj, keys, index = 0) => {
const result = obj[keys[index++]];
if (!result) {
return obj;
}
return finder(result, keys, index);
}
console.log(finder(myObj, keys));
This is pretty similar to Accessing nested JavaScript objects and arrays by string path, except with one fewer step - you already have the keys you need in the form of an array. .reduce and access the next nested value in each iteration.
const obj = {
metadata: {
correlationId: 'b24e9f21-6977-4553-abc7-416f8ed2da2d',
createdDateTime: '2021-06-15T16:46:24.247Z'
}
};
const keys = ['metadata', 'correlationId'];
const result = keys.reduce((a, key) => a[key], obj);
console.log(result);
This is my idea to solve your problem. Tell me, if is ok for you.
let x = {
metadata: {
correlationId: 'b24e9f21-6977-4553-abc7-416f8ed2da2d',
createdDateTime: '2021-06-15T16:46:24.247Z'
}
}
let fun = x => typeof x === 'string' ? console.log(x) : Object.keys(x).map( y => fun(x[y]));
fun(x);
I have sample JSON like this
`{
values:[{
"name": "Base Url",
"url": "https://kubemanagement-prod.kohls.com"
},
{
"name": "Base Url newwww",
"url": "https://batman.com"
}]
}`
Currently when I add this paticular JSON to the lodash _.keys gives me the result ["0", "1"] which is basically the index of first and second object 0 and 1.
What I exactly want is to retrieve all the keys of the JSON object including sub object properties as well. In this case ["values","0", "1","name","url"]
Does anyone knows a lodash method or a mechanism to retrieve all the keys given in complex JSON object to nth level?
language : Angular + Typescript
This function recursively gets the keys from an objects tree, using _.keys() and _.flatMap() and _.union() to combine lists of keys, and get only the unique values:
const getAllKeys = obj => _.union(
_.keys(obj),
_.flatMap(obj, o => _.isObject(o) ? getAllKeys(o) : [])
)
const arr = {"values": [{"name":"Base Url","url":"https://kubemanagement-prod.kohls.com"},{"name":"Base Url newwww","url":"https://batman.com"}]}
const result = getAllKeys(arr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
And the same idea without lodash, using Object.values() and Array.flatMap() to iterate the current object (or array), and Array.concat() and a Set to make the keys unique:
const getAllKeys = obj => [...new Set([].concat(
Object.keys(obj),
Object.values(obj).flatMap(o => typeof o === 'object' ? getAllKeys(o) : [])
))]
const arr = {"values": [{"name":"Base Url","url":"https://kubemanagement-prod.kohls.com"},{"name":"Base Url newwww","url":"https://batman.com"}]}
const result = getAllKeys(arr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Without array indexes:
const getAllKeys = obj => _.union(
_.isArray(obj) ? [] : _.keys(obj),
_.flatMap(obj, o => _.isObject(o) ? getAllKeys(o) : [])
)
const arr = {"values": [{"name":"Base Url","url":"https://kubemanagement-prod.kohls.com"},{"name":"Base Url newwww","url":"https://batman.com"}]}
const result = getAllKeys(arr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
You don't need lodash for this, Object.keys is sufficient. You just write a recursive function, writing to a Set, perhaps converting to array when you're done:
const array = [
{
"name": "Base Url",
"url": "https://kubemanagement-prod.kohls.com"
},
{
"name": "Base Url newwww",
"url": "https://batman.com"
}
];
function addAll(set, entries) {
for (const entry of entries) {
set.add(entry);
}
return set;
}
function allKeys(obj/*: object|array*/, keys/*: Set<string>*/ = new Set()) {
addAll(keys, Object.keys(obj));
for (const entry of Object.values(obj)) {
if (entry && typeof entry === "object") {
allKeys(entry, keys);
}
}
return keys;
}
console.log([...allKeys(array)]);
Or using the structure in your edit:
const array = {
values:[{
"name": "Base Url",
"url": "https://kubemanagement-prod.kohls.com"
},
{
"name": "Base Url newwww",
"url": "https://batman.com"
}]
}
function addAll(set, entries) {
for (const entry of entries) {
set.add(entry);
}
return set;
}
function allKeys(obj/*: object|array*/, keys/*: Set<string>*/ = new Set()) {
addAll(keys, Object.keys(obj));
for (const entry of Object.values(obj)) {
if (entry && typeof entry === "object") {
allKeys(entry, keys);
}
}
return keys;
}
console.log([...allKeys(array)]);
How about
const arr = {"values": [{"name":"Base Url","url":"https://kubemanagement-prod.kohls.com"},{"name":"Base Url newwww","url":"https://batman.com"}]}
let result1 = Object.keys(arr) // get the object keys which is "values"
let result2 = Object.keys(arr[result1]); // get the keys of the object name "0,1" here
let result3 = Object.keys(arr[result1][0]); // get property names of one object "name and url" here
let resutltant = result1.concat(result2, result3) // "merge array"
console.log(resutltant)
Assuming that your object properties names will remain constant
If you use typescript why don't use Object.entries or Object.values to do that?
You need to add to tsconfig the next line:
lib: [
......
"es2018",
]