I have this array.
const data = [
{ name: "A", age: "12" },
{ name: "B", age: "5" },
{ name: "C", age: "6" }
];
I want to add additional property called key to this array like this.
const data = [
{ name: "A", age: "12", key: "A12" },
{ name: "B", age: "5", key: "B5" },
{ name: "C", age: "6", key: "C6" }
];
I tired this map function and output is not the one I expect. How do I achieve this using JS map function..
const data = [
{ name: "A", age: "12"},
{ name: "B", age: "5"},
{ name: "C", age: "6"}
];
console.log(
"MAP",
data.map(element => (element.key = element.name + element.age))
);
You need to return an object from the map callback:
const data = [
{ name: "A", age: "12"},
{ name: "B", age: "5"},
{ name: "C", age: "6"}
];
console.log(
data.map(({ name, age }) => ({ name, age, key: name + age }))
);
If you wish to mutate the existing objects, then use forEach instead of .map:
const data = [
{ name: "A", age: "12"},
{ name: "B", age: "5"},
{ name: "C", age: "6"}
];
data.forEach((obj) => {
obj.key = obj.name + obj.age;
});
console.log(data);
Return element as well using the comma operator:
const data = [
{ name: "A", age: "12"},
{ name: "B", age: "5"},
{ name: "C", age: "6"}
];
console.log(data.map(element => (element.key = element.name + element.age, element)));
.as-console-wrapper { max-height: 100% !important; top: auto; }
Or just change your map callback to make it simpler with destructuring:
const data = [
{ name: "A", age: "12"},
{ name: "B", age: "5"},
{ name: "C", age: "6"}
];
console.log(data.map(({ name, age }) => ({ name, age, key: name + age})));
.as-console-wrapper { max-height: 100% !important; top: auto; }
There are more than one way to do this and the Array.map is by far the most concise and clean way to do it as already provided. Here are few other methods:
const data = [ { name: "A", age: "12" }, { name: "B", age: "5" }, { name: "C", age: "6" } ];
let from = Array.from(data, ({name, age}) => ({name, age, key: name+age}))
let assign = data.map(({name, age}) => Object.assign({name, age}, {key: name+age}))
console.log('from: ', from)
console.log('assign: ', assign)
If you want to generate a key from all values (assuming all are primitives) you can also do this:
const data = [
{ name: "A", age: "12", city: 'Miami' }, // "key": "A12Miami"
{ name: "B", age: "2", gender: 'M'}, // "key": "B2M"
];
let all = data.map(obj =>
({...obj, ...Object.fromEntries([['key', Object.values(obj).join('')]])}))
console.log(all)
This way you do not have to specify or care about the pop names etc.
Related
I am looking the following example lodash - group and populate arrays.
However I need to group by multi times like following example. What should I do? Thanks
[
{ birthdate: "1993", day: "12", category: "a", name: "Ben" },
{ birthdate: "1993", day: "13", category: "a", name: "John" },
{ birthdate: "1993", day: "14", category: "b", name: "Larry" },
{ birthdate: "1994", day: "15", category: "", name: "Nicole" },
];
to
[
{
birthdate: "1993",
birthdateDetail: [
{
category: "a",
categoryDetail: [
{ day: "12", name: "Ben" },
{ day: "13", name: "John" },
],
},
{
category: "b",
categoryDetail: [{ day: "14", name: "Larry" }],
},
],
},
{
birthdate: "1994",
birthdateDetail: [{ category: "", day: "15", name: "Nicole" }],
},
];
You could groups with an abstract approach for nested grouping by taking an object which keeps the keys for each level as well as the wanted result structure.
This approach works for arbitrary nesting.
const
data = [{ birthdate: "1993", day: "12", category: "a", name: "Ben" }, { birthdate: "1993", day: "13", category: "a", name: "John" }, { birthdate: "1993", day: "14", category: "b", name: "Larry" }, { birthdate: "1994", day: "15", category: "", name: "Nicole" }],
groups = ['birthdate', 'category'],
getEmpty = () => ({ _: [] }),
result = data
.reduce((q, o) => {
groups
.reduce((r, k) => {
const v = o[k];
if (!v) return r;
if (!r[v]) r._.push({ [k]: v, [k + 'Detail']: (r[v] = getEmpty())._ });
return r[v];
}, q)
._
.push(o);
return q;
}, getEmpty())
._;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're in the right direction: using _.groupBy will help you to group your data, but since you need two levels of nesting, you will need to run it twice:
The top level is to group by birthdate
The second level is to group by category
Since _.groupBy returns an object, we will need to use Object.entries to transform the key-value pair into an array of objects that fit the shape you have intended.
At the second level, we will need to do a final iteration to ensure that we remove the category and birthday keys from the nested data.
See proof-of-concept below:
const data = [
{ birthdate: "1993", day: "12", category: "a", name: "Ben" },
{ birthdate: "1993", day: "13", category: "a", name: "John" },
{ birthdate: "1993", day: "14", category: "b", name: "Larry" },
{ birthdate: "1994", day: "15", category: "", name: "Nicole" },
];
// Top level: group by birthdate
const dataByBirthdate = _.groupBy(data, d => d.birthdate);
// Convert object into array of objects
const transformedData = Object.entries(dataByBirthdate).map(entry => {
const [birthdate, value] = entry;
// Second level: group by category
const birthdatedetailByCategory = _.groupBy(value, d => d.category);
const birthdatedetail = Object.entries(birthdatedetailByCategory).map(entry => {
const [category, value] = entry;
// Step through all entries to ensure we remove keys of your selection
const categorydetail = value.map(d => {
delete d.birthdate;
delete d.category;
return d;
});
return { category, categorydetail };
});
return { birthdate, birthdatedetail };
});
console.log(transformedData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
This is function to group array with lodash:
const formatedResponse = _(arr)
.groupBy("birthdate")
.map((items, birthdate) => {
const birthdateDetails = _(items)
.groupBy("category")
.map((items, category) => {
return {
category,
categoryDetails: items.map(({ day, name }) => ({ day, name }))
};
})
.value();
return {
birthdate,
birthdateDetails
};
})
.value();
Maybe something like this
const data = [
{ birthdate: "1993", day: "12", category: "a", name: "Ben" },
{ birthdate: "1993", day: "13", category: "a", name: "John" },
{ birthdate: "1993", day: "14", category: "b", name: "Larry" },
{ birthdate: "1994", day: "15", category: "", name: "Nicole" },
];
const group = (data) => {
return _(data)
.groupBy('birthdate')
.map((birthdateItems, birthdate) => ({
birthdate,
birthdateDetail: _(birthdateItems)
.groupBy('category')
.map((catgoryItems, category) => ({
category,
categoryDetail: _(catgoryItems)
.map(item => _.omit(item, ['birthdate', 'category']))
.value()
}))
.value()
}))
.value();
}
console.log(group(data));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
I want to return array with properties which not matched by valuesToCompare array values
const arr = [
{value: "test1", name: "name1"},
{value: "test2", name: "name1"},
{value: "test3", name: "name1"},
{value: "test3", name: "name2"},
{value: "test4", name: "name2"},
]
const valuesToCompare = ["test1", "test2", "test3", "test4"]
expected output
[
{value: "test4", name: "name1"},
{value: "test1", name: "name2"},
{value: "test2", name: "name2"},
]
I'm not sure whether you want to match or exclude based on an array of values, so providing both:
const arr = [{
value: "test1",
name: "name1"
},
{
value: "test2",
name: "name1"
},
{
value: "test3",
name: "name1"
},
{
value: "test3",
name: "name2"
},
{
value: "test4",
name: "name2"
},
]
const valuesToCompare = ["test1", "test2"]
const excluding = arr.filter(obj => !valuesToCompare.includes(obj.value))
console.log("Excluding values:")
console.log(excluding)
const matching = arr.filter(obj => valuesToCompare.includes(obj.value))
console.log("Matching values:")
console.log(matching)
You could do like below:
group the arr by name
with each grouped, filter the value
flatten each group back into objects
const arr = [
{ value: "test1", name: "name1" },
{ value: "test2", name: "name1" },
{ value: "test3", name: "name1" },
{ value: "test3", name: "name2" },
{ value: "test4", name: "name2" },
];
const valuesToCompare = ["test1", "test2", "test3", "test4"];
const groupByName = arr.reduce((acc, el) => {
if (acc[el.name]) {
acc[el.name].push(el.value);
} else {
acc[el.name] = [el.value];
}
return acc;
}, {});
const res = Object.entries(groupByName)
.map(([k, v]) => [k, valuesToCompare.filter((vtc) => !v.includes(vtc))])
.map(([k, v]) => v.map((v) => ({ name: k, value: v })))
.flat();
console.log(res);
.as-console-wrapper { max-height: 100% !important; }
I have two arrays of objects as shown below :
categories = [
{ name: "performance", id: 1 },
{ name: "understanding", id: 2 }
]
queries = [
{ name: "A", categoryId: "1" },
{ name: "B", categoryId: "1" },
{ name: "C", categoryId: "1" },
{ name: "D", categoryId: "2" }
]
Now, using these two arrays of objects, I need following array as a result:
process = [
{ category: "performance", query: [
{ name: "A" },
{ name: "B" },
{ name: "C" }
]},
{ category: "understanding", query: [{ name: "D" }] }
]
I have to match the categoryId with process's id and then create the above array.
I have tried the following way to solve this but could not get desired result.
const test = [];
categories.forEach((element) => {
const r = que.filter((res) => res.categoryId === element.id);
queries.forEach((rt) => {
if (rt.categoryId === element.id) {
test.push({
category: element.name,
query: [{
name: rt.name,
}],
});
}
});
});
Is this possible using any built in array methods in JavaScript?
Thanks in advance
Using Array.reduce, you can group queries by categoryId.
Based on that groupedBy object, using Array.map, you can get the result you want.
const categories = [{
name: "performance",
id: "1"
},{
name: "understanding",
id: "2"
}];
const queries = [{
name: "A",
categoryId: "1"
}, {
name: "B",
categoryId: "1"
}, {
name: "C",
categoryId: "1"
}, {
name: "D",
categoryId: "2"
}];
const groupByQueries = queries.reduce((acc, cur) => {
acc[cur.categoryId] ?
acc[cur.categoryId].push({ name: cur.name })
: acc[cur.categoryId] = [ { name: cur.name } ];
return acc;
}, {});
const result = categories.map(({ name, id }) => ({
category: name,
query: groupByQueries[id]
}));
console.log(result);
categories = [{name: "performance", id: 1},{name: "understanding", id: 2}];
queries = [{name: "A", categoryId: "1"}, {name: "B", categoryId: "1"}, {name: "C", categoryId: "1"}, {name: "D", categoryId: "2"}]
const test = [];
categories.forEach((element) => {
let temp = []
queries.map(item =>{
if(element.id.toString() === item.categoryId)
temp.push({name: item.name})
})
test.push({category:element.name,query:temp})
});
console.log(test)
When there are multiple entries, I only want to append "_1","_2"....etc to json object, making sure no data is lost. If this is input:
names_array = [
{name: "a", age: 15},
{name: "a", age: 16},
{name: "a", age: 17},
{name: "b", age: 18}
{name: "b", age: 19}];
I want the output to be
names_array_new = [
{name: "a", age: 15},
{name: "a_1", age: 16},
{name: "a_2", age: 17},
{name: "b", age: 18}
{name: "b_1", age: 19}
];
I have searched for this but only found how to remove duplicates when entire objects are same or retain the last found value.
there are possibly better solutions, but i came up with such quick snippet. take it and make better.
name_changer = (n) => {
splitted = n.split("_");
if(splitted.length > 1) {
name = splitted[0];
ord = parseInt(splitted[1]);
return `${name}_${ord+1}`
} return `${n}_${1}`
}
stack = []
names_array = [
{name: "a", age: 15},
{name: "a", age: 16},
{name: "a", age: 17},
{name: "b", age: 18},
{name: "b", age: 19}
];
names_array.forEach(obj => {
if (stack.indexOf(obj.name) > -1) {
obj.name = name_changer(obj.name);
} stack.push(obj.name);
})
console.log(names_array);
You can use the function Array.prototype.reduce to generate the desired output.
The handler basically keeps the previous processed values in order to save the current count and finally we get the result from the accumulator.
let arr = [ {name: "a", age: 15}, {name: "a", age: 16}, {name: "a", age: 17}, {name: "b", age: 18}, {name: "b", age: 19}],
{result} = arr.reduce((a, {name: n, age}) => {
let key = a.counts[n] = (a.counts[n] || a.counts[n] === "" ? (+a.counts[n] + 1) : ""),
name = `${n}${key === "" ? "" : "_"}${key}`;
a.result.push({name, age});
return a;
}, {counts: {}, result: []});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can simply check the index and name of each a and b and then rename the value of that object keys with count++ with increment of count on each loop.
Just FYI - This can be improved more so wait for other solutions to come as well and choose what suits you best but this is simple and straight to your desired output!
Expected Output Demo:
var names_array = [{
name: "a",
age: 15
},
{
name: "a",
age: 16
},
{
name: "a",
age: 17
},
{
name: "b",
age: 18
}, {
name: "b",
age: 19
}
];
var countA = 1 //count increase for a
var countB = 1 //count increase for b
names_array.forEach(function(obj, index) {
if (obj.name == 'a' && index >= 1) {
obj.name = obj.name + '_' + countA++; //rename a
}
if (obj.name == 'b' && index >= 4) {
obj.name = obj.name + '_' + countB++; //rename b
}
});
console.log(names_array)
You could use a lookup object with key-value pairs of name value and its occurence
const nameValueLookup = {}
const namesArray = [
{ name: "a", age: 15 },
{ name: "a", age: 16 },
{ name: "a", age: 17 },
{ name: "b", age: 18 },
{ name: "b", age: 19 },
]
const res = namesArray.map((obj) => {
if (nameValueLookup[obj.name]) {
return { ...obj, name: `${obj.name}_${nameValueLookup[obj.name]++}` }
} else {
nameValueLookup[obj.name] = 1
return obj
}
})
console.log(res)
This is my Array in JavaScript, I want to merge teacher object below into combine single object to perform operations further.
const data = [
{
name: "ab",
class: 1,
grade: "A",
teacher: {
teacherName: "tab",
age: 34,
school: "ab pblc scl"
}
},
{
name: "cd",
class: 2,
grade: "B",
teacher: {
teacherName: "efg",
age: 35,
school: "cd pblc scl"
}
}
];
This is my Expected output. Here teacher object is combine with other single objects. Any idea how can I do this ?
const data = [
{
name: "ab",
class: 3,
grade: "B",
teacherName: "kio",
age: 38,
school: "ab pblc scl"
},
{
name: "de",
class: 2,
grade: "B",
teacherName: "tde",
age: 36,
school: "de pblc scl"
}
}
];
Any help will be appreciated
You could destructure teacher and spread the rest of the array with teacher to a new object.
Methods:
destructuring assignment to teacher,
result = data.map(({ teacher, ...object }) => ({ ...object, ...teacher }));
^ ^^^^^^^ ^
rest in object destructuring for getting all other properties,
result = data.map(({ teacher, ...object }) => ({ ...object, ...teacher }));
^ ^^^^^^^^^ ^
spread syntax ... for getting copies of own enumerable properties of the object
result = data.map(({ teacher, ...object }) => ({ ...object, ...teacher }));
^ ^^^^^^^^^ ^^^^^^^^^^ ^
const
data = [{ name: "ab", class: 1, grade: "A", teacher: { teacherName: "tab", age: 34, school: "ab pblc scl" } }, { name: "cd", class: 2, grade: "B", teacher: { teacherName: "efg", age: 35, school: "cd pblc scl" } }],
result = data.map(({ teacher, ...object }) => ({ ...object, ...teacher }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use spread operator to do it.
const data = [
{
name: "ab",
class: 1,
grade: "A",
teacher: {
teacherName: "tab",
age: 34,
school: "ab pblc scl"
}
},
{
name: "cd",
class: 2,
grade: "B",
teacher: {
teacherName: "efg",
age: 35,
school: "cd pblc scl"
}
}
];
const newData = data.map(d => {
const dClone = Object.assign({},d);
delete dClone.teacher;
return {
...dClone,
...d.teacher
}
})
console.log(newData);