Related
I see that all the loops for objects returns the key as string and the value, but I want to operate on the keys of the object itself. If I have this object:
const data = {
person1: [
{ id: 1, name: Mike, age: 24 },
{ id: 2, name: Bob, age: 31 }
],
person2: [
{ id: 3, name: Christin, age: 21 },
{ id: 4, name: Michelle, age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
const persons = Object.keys(data).map(person => ...)
}
I wanted to loop through data and run .includes on each person in order to remove them by the id, but I am at a loss on how to do that.
You can loop through all keys and delete that the person you want by id using the filter() method
const removePersonById = (id) => {
var all = Object.keys(data);
for(let person of all){
data[person] = data[person].filter(a => a.id!=id);
}
}
You could get the values and find the index. Then splice.
const
removePersonById = id => {
Object.values(data).forEach(a => {
const index = a.findIndex(o => o.id === id);
if (index !== 0) a.splice(index, 1);
});
};
You could use .some()
const data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
Object.keys(data).map(person => {
if (data[person].some(p => p.id === id)) delete data[person];
})
}
removePersonById(3)
console.log(data)
Use Object.entries() so you can iterate over the keys and values together. Then you can test the value to see if the id is found.
Then use the delete operator to remove that key from the object.
const removePersonById = id => {
delete data[id];
};
const data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
};
const removePersonById = (id) =>
Object.entries(data).forEach(([key, value]) => {
if (value.some(({id: personid}) => personid == id)) {
delete data[key];
}
});
removePersonById(3);
console.log(data);
let data = {
person1: [
{ id: 1, name: "Mike", age: 24 },
{ id: 2, name: "Bob", age: 31 }
],
person2: [
{ id: 3, name: "Christin", age: 21 },
{ id: 4, name: "Michelle", age: 33 }
],
}
const removePersonById = (id) => {
// Check which person the id belongs to and remove that person
data = Object.keys(data).reduce((acc,key) => {
if(data[key].some(person=>person.id===id)) return acc
acc[key]= data[key]
return acc
}, {})
console.log(`Remove person with ID ${id}: `,data)
}
removePersonById(1)
Hello I m trying to map through a json file and add a new property to every object in it.
DATA.JSON
const arr = [
{
index: 0,
name: "John",
hair: "Brown",
},
{
index: 1,
name: "Bob",
hair: "Blonde",
},
];
APP.JS
const data = require("./data.json");
const items = data.map((item) => {
return ????
});
I want to map through the array, and add a "age" property to every index with a value of 30 or even just an empty value would be ok. with result something like this:
RESULT
const a =
[
{
index: 0,
name: "John",
hair: "Brown",
age: 30
},
{
index: 1,
name: "Bob",
hair: "Blonde",
age: 30
},
];
const arr = [
{
index: 0,
name: "John",
hair: "Brown",
},
{
index: 1,
name: "Bob",
hair: "Blonde",
},
];
const result = arr.map((obj) => {
return { ...obj, age: 30 };
});
console.log(result);
You can also make it one-liner
const result = arr.map((obj) => ({ ...obj, age: 30 }));
If you want to print only hair of each index then
const arr = [
{
index: 0,
name: "John",
hair: "Brown",
},
{
index: 1,
name: "Bob",
hair: "Blonde",
},
];
const result = arr.map((obj) => {
return { ...obj, age: 30 };
});
const hairs = result.map((o) => o.hair);
console.log(hairs); // Printing as an array
console.log(hairs.toString()); // Printing as comma separated value
Hello you could do something like this:
const data = [
{
index:0,
name: "John",
hair: "Brown",
},
{
index:1,
name: "Bob",
hair: "Blonde",
},
];
const newData = data.map(item => ({
...item,
newProp: 'hello world',
}));
// Print whole data:
console.log(newData);
// Filter specific properties
const hair = newData.map(item => item['hair'])
console.log('only hair ->', hair);
Side note, you don't need the index property in the object since you can get it while looping.
map(currentItem, index) Docs
If you want to print specific properties of the object you can do as such:
console.log(newData.map(item => item['hair']));
Suppose I got an object defined as such:
const me = {
id: 1,
name: 'James',
age: 40,
family: {
mother: {
id: 101,
name: 'Bea',
age: 66
},
father: {
id: 102,
name: 'Martin',
age: 69
},
children: [
{
id: 11,
name: 'Tom',
age: 18,
},
{
id: 12,
name: 'Nancy',
age: 13,
},
],
},
}
How does one easily access a value by just giving an array of strings of the chained properties' names?
For example, calling:
search(me, ['family', 'father', 'age'])
which would be the same as:
me['family']['father']['age']
would return 69.
PS:
What about having search(me, ['family', 'children', 'name']) return ['Tom', 'Nancy']?
PSS:
Or even search(me, ['family', 'children', ['name', 'age']]) returning
[
{
name: 'Tom',
age: 18
},
{
name: 'Nancy',
age: 13
}
]
EDIT:
I went checking out lodash/deepdash libraries, but couldn't really figure it out by myself.
You can do that with this simple recursive function which takes an array as the query:
const me = {
id: 1,
name: 'James',
age: 40,
family: {
mother: {
id: 101,
name: 'Bea',
age: 66
},
father: {
id: 102,
name: 'Martin',
age: 69
},
children: [
{
id: 11,
name: 'Tom',
age: 18,
},
{
id: 12,
name: 'Nancy',
age: 13,
},
],
},
}
function search(obj, [first, ...rest]) {
return rest.length ? search(obj[first], rest) : obj[first];
}
const result = search(me, ['family', 'father', 'age']);
console.log(result);
Though it's bit lengthy, you could try this for all your combinations.
const me={id:1,name:'James',age:40,family:{mother:{id:101,name:'Bea',age:66},father:{id:102,name:'Martin',age:69},children:[{id:11,name:'Tom',age:18,},{id:12,name:'Nancy',age:13,},],},}
function search(data, searchPattern) {
const keys = [...searchPattern];
//picking last key and it's corresponding value
const lastKey = keys.pop();
const resultInst = keys.reduce((acc,key)=>{
return acc[key];
}, data);
// if it's array iterating it further to construct the response
if (Array.isArray(resultInst)) {
return resultInst.map(inst => {
if (Array.isArray(lastKey)) {
return lastKey.reduce((accInner,key) => {
accInner[key] = inst[key];
return accInner;
}, {});
} else {
return inst[lastKey];
}
});
} else {
// else just returning property's value
return resultInst[lastKey];
}
}
console.log(search(me, ['family', 'father', 'age']))
console.log(search(me, ['family', 'children', 'name']))
console.log(search(me, ['family', 'children', ['name', 'age']]))
Some interesting requirements you have there! Here is an all-in-one answer using object-scan and lodash
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/lodash#4.17.21"></script>
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/object-scan#18.1.2/lib/index.min.js';
const myData = { id: 1, name: 'James', age: 40, family: { mother: { id: 101, name: 'Bea', age: 66 }, father: { id: 102, name: 'Martin', age: 69 }, children: [{ id: 11, name: 'Tom', age: 18 }, { id: 12, name: 'Nancy', age: 13 }] } };
const search = (data, needle) => objectScan([needle], {
reverse: false,
rtn: ['key', 'value'],
useArraySelector: false,
afterFn: (state) => {
if (state.result.length === 0) {
state.result = undefined;
} else if (needle.includes('{')) {
const prefixLength = lodash
.zip(...state.result.map(([k]) => k))
.findIndex((e) => new Set(e).size > 1);
const result = [];
state.result.forEach(([k, v]) => lodash.set(result, k.slice(prefixLength), v));
state.result = result;
} else if (
state.result.length === 1
&& state.result.every(([k]) => k.every((p) => typeof p === 'string'))
) {
state.result = state.result[0][1];
} else {
state.result = state.result.map(([k, v]) => v);
}
}
})(data);
console.log(search(myData, 'family.father.age'));
// => 69
console.log(search(myData, 'family.children.name'));
// => [ 'Tom', 'Nancy' ]
console.log(search(myData, 'family.children.{age,name}'));
// => [ { name: 'Tom', age: 18 }, { name: 'Nancy', age: 13 } ]
console.log(search(myData, 'family.father.unknown'));
// => undefined
</script>
Disclaimer: I'm the author of object-scan
This is my code, I want to create another filtered array like the example below, I have 2 arrays and want to add score information to it, I know it's simple but can't find the solution
const wishesData = [
{
name: "Peter",
presents: ["coffee", "holidays"]
},
{
name: "Mario",
presents: ["coffee", "videogames"]
},
{
name: "Amanda",
presents: ["computer", "tattoo"]
}
]
const scoresData= [
{
name: "Peter",
score: 10
},
{
name: "Mario",
score: 2.3
},
{
name: "Amanda",
score: 1.1
}
]
const result = wishesData.map((ele) => {
return {
...ele,
score: scoresData.find(s=> s.name === ele.name? s.score: 0)
}
})
console.log("este es el resultado=>",result)
I want to modify the array wishesData adding "score" to all objects inside and get to look like this example:
{
name: "Mario",
presents: ["coffee", "videogames"],
score: 2.3
}
Please check the example and correction and suggestions.
Correction: scoresData.find(s=> s.name === ele.name? s.score: 0) - here you do not close bracket for Array.find and try to access it's property within find. In your code, you will get scoreData object instead of score.
const match = scoresData.find(s=> s.name === ele.name); // -> ? s.score: 0)
return match ? match.score : 0;
// or simply
const score = scoresData.find(s=> s.name === ele.name)?.score || 0;
Suggestion: it will take O(N^2) time. All iteration for wishesData need another iteration scoresData for each. Why don't you use reduce provided in example?
const scoreMap = scoresData.reduce((a, c) => ({
...a,
[c.name]: c.score
}), {})
// you can easy to find score by
const result = wishesData.map((ele) => {
return {
...ele,
score: scoreMap[ele.name] || 0,
}
})
Thanks
const wishesData = [{
name: "Peter",
presents: ["coffee", "holidays"]
},
{
name: "Mario",
presents: ["coffee", "videogames"]
},
{
name: "Amanda",
presents: ["computer", "tattoo"]
}
]
const scoresData = [{
name: "Peter",
score: 10
},
{
name: "Mario",
score: 2.3
},
{
name: "Amanda",
score: 1.1
}
]
const scoreMap = scoresData.reduce((a, c) => ({
...a,
[c.name]: c.score
}), {})
const result = wishesData.map((ele) => {
return {
...ele,
score: scoreMap[ele.name] || 0,
}
})
console.log("este es el resultado=>", result)
And this is just editing of your origin code
const wishesData = [{
name: "Peter",
presents: ["coffee", "holidays"]
},
{
name: "Mario",
presents: ["coffee", "videogames"]
},
{
name: "Amanda",
presents: ["computer", "tattoo"]
}
]
const scoresData = [{
name: "Peter",
score: 10
},
{
name: "Mario",
score: 2.3
},
{
name: "Amanda",
score: 1.1
}
]
const result = wishesData.map((ele) => {
return {
...ele,
score: scoresData.find(s => s.name === ele.name)?.score || 0
}
})
console.log("este es el resultado=>", result)
You return the whole object, just return the score:
const wishesData = [{
name: "Peter",
presents: ["coffee", "holidays"]
},
{
name: "Mario",
presents: ["coffee", "videogames"]
},
{
name: "Amanda",
presents: ["computer", "tattoo"]
},
{
name: "Another",
presents: ["computer", "tattoo"]
}
]
const scoresData = [{
name: "Peter",
score: 10
},
{
name: "Mario",
score: 2.3
},
{
name: "Amanda",
score: 1.1
}
]
const result = wishesData.map(ele => {
const match = scoresData.find(s => s.name === ele.name)
return { ...ele, score: match ? match.score : 0 }
})
console.log("este es el resultado=>", result)
const wishesWithScores = wishesData.map(wishObject => {
const descriptor = wishObject.name;
const { score } = scoresData.find(({ name }) => name === descriptor);
return {
...wishObject,
score
}
});
Maybe someone can give me idea how can i do it. So I have array of names ["Tom", "Jane", "Mike", "John"] and also I have array of objects which are purchase reports:
[
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 }
]
I need to get objects which represent a person and the amount they spend overall. [{ name: "Tom", amount: 15 }, { name: "Mike", amount: 25 }, ... I hope you get the idea. How can I achieve this? I try to map the names and filter array of objects but get undefined.
Use a combination of map, filter and reduce to boil down the data:
The first .map is building the object structure, you want e.g. {name: '...', amount: <val>}
in order to get the value for each of the names, you filter the spending by name and reduce the outputed values by adding them.
const names = ["Tom", "Jane", "Mike", "John"];
const spendings = [{
date: "19/02/2019",
name: "Mike",
amount: 10
}, {
date: "20/02/2019",
name: "Mike",
amount: 15
}, {
date: "21/10/2019",
name: "Jane",
amount: 25
}, {
date: "22/03/2019",
name: "John",
amount: 30
}, {
date: "19/03/2019",
name: "Tom",
amount: 15
}];
const result = names.map(name => {
return {
name,
amount: spendings.filter(spending => spending.name === name).reduce((sum, {
amount
}) => sum + amount, 0)
};
});
console.log(result);
You can try this code:
const data = [
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
];
const names = ["Tom", "Jane", "Mike", "John"];
const results = names.map((name) => ({
name,
amount: data
.filter(({ name: dataName }) => dataName === name)
.reduce((total, { amount }) => total + amount, 0),
}));
console.log(results);
.as-console-wrapper { min-height: 100%!important; top: 0; }
You can set it up however you like using the javascript filter method.
Eg. If you want to get entries in the array that match name and amount you can write a function like this:
const result = (name, cost) => array.filter(customer => {
return name == customer.name && cost == customer.cost;
});
Running result("Jane", 25) will return this:
[{date: "21/10/2019", name: "Jane", amount: 25}]
You could create an object with the wanted names and add the amount to each property.
const
names = ["Tom", "Jane", "Mike", "John"],
purchases = [{ date:"19/02/2019", name: "Mike", amount: 10 }, { date: "20/02/2019", name: "Mike", amount: 15 }, { date: "21/10/2019", name: "Jane", amount: 25 }, { date: "22/03/2019", name: "John", amount: 30 }, { date: "19/03/2019", name: "Tom", amount: 15 }],
result = purchases.reduce(
(object, { name, amount }) => (object[name] += amount, object),
Object.fromEntries(names.map(name => [name, 0]))
);
console.log(result);
Use Array.reduce on your report array.
And reduce report array into dictionary of overall report for each name.
try first to solve it by your own.
this is my solution :
const dictionaryReports = reports.reduce((prev,curr)=>{
if(!prev[curr.name]) {
return {...prev,prev[curr.name] : curr}
}else{
return {
...prev,
prev[curr.name]:
{
...prev[curr.name],
amount : prev[curr.name].amount + curr.amount
}
}
}
},{})
the output will be :
dictionaryReports = {
Mike : {name:"Mike",amount:25},
Tom : {name:"Tom",amount:15}
}
then you can do
Object.values(dictionaryReports)
You can use the array reduce method on purchases. You don't need the array of names I think it looks useless for the result.
const purchases = [
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 }
]
const overall = purchases.reduce((acc, curr) => {
const currentUser = acc.find(x => x.name === curr.name);
if(currentUser) {
currentUser.amount += curr.amount;
} else {
acc.push({name:curr.name,amount: curr.amount})
}
return acc;
}, []);
This approach is as generic as can be. It combines a map and a reduce method in a way that any data from a given dataset (list of data) and a corresponding (target) value list can be collected for the latter from the former by just providing a start configuration to the above mentioned map-reduce combination ...
const dataset = [
{ date: "19/03/2019", name: "Jerry", amount: 45 },
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
{ date: "19/03/2019", name: "Jerry", amount: 15 }
];
function aggregateTargetItemValueFromSourceKey(collector, item) {
const { aggregateValue, sourceKey, targetKey, targetItem } = collector;
if (targetItem[targetKey] === item[targetKey]) {
targetItem[sourceKey] = aggregateValue(targetItem[sourceKey], item[sourceKey]);
}
return collector;
}
function createTargetItemFromBoundDatasetConfig(targetValue) {
const { dataset, aggregateValue, initialValue, sourceKey, targetKey } = this;
return dataset.reduce(aggregateTargetItemValueFromSourceKey, {
aggregateValue,
sourceKey,
targetKey,
targetItem: {
[targetKey]: targetValue,
[sourceKey]: initialValue
}
}).targetItem;
}
console.log(
["Tom", "Jane", "Mike", "John"]
.map(createTargetItemFromBoundDatasetConfig, {
aggregateValue: ((targetValue, sourceValue) => targetValue + sourceValue),
initialValue: 0,
sourceKey: 'amount',
targetKey: 'name',
dataset
})
);
console.log(
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
.map(createTargetItemFromBoundDatasetConfig, {
aggregateValue: ((targetValue, sourceValue) => targetValue.concat(sourceValue)),
initialValue: [],
sourceKey: 'name',
targetKey: 'amount',
dataset
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
The second approach is a straightforward one, thus it is less flexible in the result it does produce. Nevertheless, there is at least the option of plainly aggregating the data from any item in the provided dataset, or, as the OP unintentionally might have hinted by the provided name list, one can use the latter for filtering only those items from the dataset list that are actually feature one of its names. ...
const dataset = [
{ date: "19/03/2019", name: "Jerry", amount: 45 },
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
{ date: "19/03/2019", name: "Jerry", amount: 15 }
];
const itemNameList = ["Tom", "Jane", "Mike", "John"];
function aggregateItemAmountByItemNameWithOptionalNameCeck(collector, item) {
const { checklist, index, list } = collector;
const itemName = item.name;
const isProceed = (!Array.isArray(checklist) || checklist.includes(itemName))
if (isProceed) {
let targetItem = index[itemName];
if (!targetItem) {
targetItem = index[itemName] = {
name: itemName,
amount: 0
};
list.push(targetItem);
}
targetItem.amount = targetItem.amount + item.amount;
}
return collector;
}
console.log(
'with name check ... ',
dataset.reduce(aggregateItemAmountByItemNameWithOptionalNameCeck, {
checklist: itemNameList,
index: {},
list: []
}).list
);
console.log(
'without name check ... ',
dataset.reduce(aggregateItemAmountByItemNameWithOptionalNameCeck, {
index: {},
list: []
}).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }