count occurrences of two keys in objects in array - javascript

I have the following array with objects and used the following code to creating a tally with the key "id":
var arr=[
{ id: 123,
title: "name1",
status: "FAILED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 1234,
title: "name2",
status: "FAILED"
},
{
id: 1234,
title: "name2",
status: "PASSED"
}
];
const test =arr.reduce((tally, item) => {
if (!tally[item.id]) {
tally[item.id] = 1;
} else {
tally[item.id] = tally[item.id] + 1;
}
return tally;
}, {});
console.log(test);
Now what I want to do is to modify the tally to take in consideration the key status as well so the result will be somthing like:
[
{id:123, status:"PASSED", tally:3},
{id:123, status:"FAILED", tally:1},
{id:1234, status:"PASSED", tally:1},
{id:1234, status:"FAILED", tally:1}
]
Any idea? Thanks!

Just make the key item.id + item.status, then it's a simple assignment
const res = Object.values(arr.reduce((a, b) => {
a[b.id + b.status] = Object.assign(b, {tally: (a[b.id + b.status] || {tally: 0}).tally + 1});
return a;
}, {}));
console.log(res);
<script>
const arr=[
{ id: 123,
title: "name1",
status: "FAILED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 123,
title: "name1",
status: "PASSED"
},
{
id: 1234,
title: "name2",
status: "FAILED"
},
{
id: 1234,
title: "name2",
status: "PASSED"
}
];
</script>

here you go
const test = arr.reduce((acc, item) => {
let found = acc.find(obj => obj.id === item.id && obj.status === item.status)
if (typeof found === "undefined") {
item.tally = 1
acc.push(item);
} else {
found.tally++;
}
return acc;
}, []);

You should group your items first using key that will contain both id and status:
const result = arr.reduce((acc, item) => {
const key = item.id + item.status;
acc[key] = acc[key] || { ...item, tally: 0 };
acc[key].tally++;
return acc;
}, {});
console.log( Object.values(result) );
Output:
[
{ id: 123, title: 'name1', status: 'FAILED', tally: 1 },
{ id: 123, title: 'name1', status: 'PASSED', tally: 3 },
{ id: 1234, title: 'name2', status: 'FAILED', tally: 1 },
{ id: 1234, title: 'name2', status: 'PASSED', tally: 1 },
]

Simply create a key with combination of id and status. And make a map using it. After that you can simply get the desired result from that.
Try the following:
var arr=[{id:123,title:"name1",status:"FAILED"},{id:123,title:"name1",status:"PASSED"},{id:123,title:"name1",status:"PASSED"},{id:123,title:"name1",status:"PASSED"},{id:1234,title:"name2",status:"FAILED"},{id:1234,title:"name2",status:"PASSED"}];
const map =arr.reduce((tally, item) => {
tally[item.id+"_"+item.status] = (tally[item.id+"_"+item.status] || 0) +1;
return tally;
}, {});
const result = Object.keys(map).map((a)=>{
var obj = {
id : a.split("_")[0],
status : a.split("_")[1],
tally : map[a]
};
return obj;
});
console.log(result);

Related

Merging two arrays of objects Javascript / Typescript

I have two arrays of objects which looks something like this:
const users = [
{
status: 'failed',
actionName: 'blabla',
userId: 1,
},
{
status: 'success',
actionName: 'blablabla',
userId: 2,
},
];
Second one
const usersDetails = [
{
name: 'Joseph',
id: 1,
},
{
name: 'Andrew',
id: 2,
},
];
I want to check if userId is equal to id and if so then push the name from usersDetails into users objects. So output would look like this:
const users = [
{
status: 'failed',
actionName: 'blabla',
userId: 1,
name: 'Joseph'
},
{
status: 'success',
actionName: 'blablabla',
userId: 2,
name: 'Andrew'
}];
The easiest solution would be to do:
const users = [
{
status: 'failed',
actionName: 'blabla',
userId: 1,
},
{
status: 'success',
actionName: 'blablabla',
userId: 2,
},
];
const usersDetails = [
{
name: 'Joseph',
id: 1,
},
{
name: 'Andrew',
id: 2,
},
];
const getAllUserInfo = () => users.map(user => {
const userExtraInfo = usersDetails.find(details => details.id === user.userId)
const fullUser = {...user, ...userExtraInfo}
delete fullUser.id
return fullUser
})
console.log(getAllUserInfo())
const users = [ { status: 'failed', actionName: 'blabla', userId: 1, }, { status: 'success', actionName: 'blablabla', userId: 2, }, ];
const usersDetails = [ { name: 'Joseph', id: 1, }, { name: 'Andrew', id: 2, }, ];
const newUsers = users.map(user => {
user.name = usersDetails.find(u => u.id === user.userId)?.name;
return user;
});
console.log(newUsers);
You can try this code :
let result = users.map(user => ({...user, ...usersDetails.find(userDetail => userDetail.id == user.userId) }));
console.log(result);
If you only want to get name from the second array :
let result = users.map(user => ({...user, 'name': usersDetails.find(userDetail => userDetail.id == user.userId).name }));
If you want to get all properties exepted id ::
let result = users.map(user => {
let result = {...user, ...usersDetails.find(userDetail => userDetail.id == user.userId) }
delete result.id;
return result;
});
Hope this answer will work for you
const users = [
{
status: "failed",
actionName: "blabla",
userId: 1,
},
{
status: "success",
actionName: "blablabla",
userId: 2,
},
];
const usersDetails = [
{
name: "Joseph",
id: 1,
},
{
name: "Andrew",
id: 2,
},
];
users.map((e) => {
usersDetails.find((_e) => {
if (e.userId === _e.id) {
e.name = _e.name;
}
});
});
console.log(users);
you can do something like this using a single loop
const users = [
{
status: "failed",
actionName: "blabla",
userId: 1,
},
{
status: "success",
actionName: "blablabla",
userId: 2,
},
];
const usersDetails = [
{
name: "Joseph",
id: 1,
},
{
name: "Andrew",
id: 2,
},
];
const result = Object.values([...users, ...usersDetails].reduce((res, {userId, id,...item}) => {
const key = id || userId
return {
...res,
[key]: {...(res[key] || {userId: key}), ...item}
}
}, {}))
console.log(result);
const users = [{
status: 'failed',
actionName: 'blabla',
userId: 1,
},
{
status: 'success',
actionName: 'blablabla',
userId: 2,
},
];
const usersDetails = [{
name: 'Joseph',
id: 1,
},
{
name: 'Andrew',
id: 2,
},
];
users.forEach(each => {
const found = usersDetails.find(detail => detail.id === each.userId);
if (found) {
each.name = found.name;
}
});
console.log(users);

get keys from the nested array of objects

I am looking for a function that can mutate my data i.e array of object with a nested object. It will include keys that have object/array values (it should only include keys with immediate string/number/boolean values).
Example
[
{
id: 1,
person1: {
firstname: "test1",
lastname: 'singh',
address: {
state: "maharashtra",
}
}
},
{
id: 2,
person2: {
firstname: "test2",
lastname: 'rathod',
address: {
state: "kerala",
}
}
},
{
id: 3,
person3: {
firstname: "test3",
lastname: 'gokale',
address: {
state: "Tamilnadu",
}
}
}
]
Expected output
[
{
title: 'person1',
value: 'person.id'
},
{
title: 'person1',
value: 'person.firstname'
},
{
title: 'person1',
value: 'person.lastname'
},
{
title: 'person1',
value: 'person.address'
},
{
title: 'person1',
value: 'person.address.state'
},
...sameforOthers
]
Basically, I need a function that will get an array and will return an array of objects as a given above as expected output
Thanks in advance
I have come up with a solution. below is the link for code sandbox for the
https://codesandbox.io/s/heuristic-rubin-yy2cyy?file=/src/index.js:0-213same
const suggestions = [
{
id: 1,
person1: {
id: "1",
firstname: "test1",
lastname: "singh",
address: {
state: "maharashtra"
},
attributeId: "fhgfgh"
}
}
];
const typeList = ["string", "number", "boolean"];
const getLabelValue = (itemList, initalArr, parentId) => {
if (Array.isArray(itemList)) {
itemList.forEach((currentItem, idx) => {
const id = parentId ? `${parentId}.${idx}` : idx;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
} else {
let keys = Object.keys(itemList);
keys.forEach((currentKey) => {
let currentItem = itemList[currentKey];
const id = parentId ? `${parentId}.${currentKey}` : currentKey;
if (typeList.includes(typeof currentItem)) {
initalArr.push({
title: id,
value: id
});
} else {
getLabelValue(currentItem, initalArr, id);
}
});
}
return initalArr;
};
console.log(">>>>>>>>>", getLabelValue(suggestions, [], ""));

Return last value with recursion - Javascript

Hi all I have following data:
const section = {
fileds: [
{ id: "some Id-1", type: "user-1" },
{
child: [
{ id: "some Id-2", type: "user-2" },
{ fileds: [{ id: "kxf5", status: "pending" }] },
{ fileds: [{ id: "ed5t", status: "done" }] }
]
},
{
child: [
{ id: "some Id-3", type: "teacher" },
{ fileds: [{ id: "ccfr", status: null }] },
{ fileds: [{ id: "kdpt8", status: "inProgress" }] }
]
}
]
};
and following code:
const getLastIds = (arr) =>
arr.flatMap((obj) => {
const arrayArrs = Object.values(obj).filter((v) => Array.isArray(v));
const arrayVals = Object.entries(obj)
.filter(([k, v]) => typeof v === "string" && k === "id")
.map(([k, v]) => v);
return [...arrayVals, ...arrayArrs.flatMap((arr) => getLastIds(arr))];
});
console.log(getLastIds(section.fileds));
// output is (7) ["some Id-1", "some Id-2", "kxf5", "ed5t", "some Id-3", "ccfr", "kdpt8"]
My code doing following, it printing in new array all ids.
It's working but I don't need all ids.
I need to return only last id in array and I should use recursion.
The output should be
(4) [" "kxf5", "ed5t", "ccfr", "kdpt8"]
P.S. here is my code in codesandbox
Is there a way to solve this problem with recursion? Please help to fix this.
You can do it with reduce.
function getLastIds (value) {
return value.reduce((prev, cur) => {
if (cur.id) {
return [ ...prev, cur.id ];
} else {
let key = ('child' in cur) ? 'child' : 'fileds';
return [ ...prev, ...getLastIds (cur[key]) ]
}
}, []);
}
You could check if a certain key exists and take this property for mapping id if status exists.
const
getValues = data => {
const array = Object.values(data).find(Array.isArray);
return array
? array.flatMap(getValues)
: 'status' in data ? data.id : [];
},
section = { fileds: [{ id: "some Id-1", type: "user-1" }, { child: [{ id: "some Id-2", type: "user-2" }, { fileds: [{ id: "kxf5", status: "pending" }] }, { fileds: [{ id: "ed5t", status: "done" }] }] }, { child: [{ id: "some Id-3", type: "teacher" }, { fileds: [{ id: "ccfr", status: null }] }, { fileds: [{ id: "kdpt8", status: "inProgress" }] }] }] },
result = getValues(section);
console.log(result);

How to sum each value inside array of object to new variable

I have a data like this :
const fund =
[
{
id: 1234,
totalAmount: 0,
data:
[
{
id: 1234,
amount: '4.000'
},
{
id: 1234,
amount: '3.000'
}
]
},
{
id: 12345,
totalAmount: 0
},
{
id: 123456,
totalAmount: 0
data:
[
{
id: 123456,
amount: '3.000'
},
{
id: 123456,
amount: '5.000'
}
]
}
]
I want to sum the amount inside of data each id to a key called totalAmount. But not all the parent id have data key.
here's my desired output :
const fund =
[
{
id: 1234
data:
[
{
id: 1234,
amount: '4.000'
},
{
id: 1234,
amount: '3.000'
}
],
totalAmount: 7000
},
{
id: 12345,
totalAmount: 0
},
{
id: 123456,
data:
[
{
id: 123456,
amount: '3.000'
},
{
id: 123456,
amount: '5.000'
}
],
totalAmount: 8000
}
]
I was trying with this code :
fund.forEach((elA, i) => {
if (elA.data) {
const total = funders[i].data.reduce((acc, curr) => {
acc += parseInt(curr.amount.replace(/\./g, ''))
return acc
})
fund[i] = total ? {...elA, totalAmount: total} : elA;
}
})
But it's not summing like i want.
Where's my mistake ?
Please ask me if you need more information if it's still not enough to solve that case.
You need to define the initial value for the reduce iterator.
fund.forEach((elA, i) => {
if (elA.data) {
const total = funders[i].data.reduce((acc, curr) => {
acc += parseInt(curr.amount.replace(/\./g, ''))
return acc
}, 0)
fund[i] = total ? {...elA, totalAmount: total} : elA;
}
});
Another alternative for the same code:
fund.forEach(elA => {
if (elA.data) {
const total = elA.data.reduce((acc, curr) => {
return acc + parseInt(curr.amount.replace(/\./g, ''))
}, 0)
elA.totalAmount = total;
}
});

Advanced filter object in js

I'm trying filter Object of Arrays with Object but i don't have idea what can I do it.
Sample:
{
245: [
{
id: "12",
name: "test",
status: "new"
},
{
id: "15",
name: "test2",
status: "old"
},
{
id: "12",
name: "test2",
status: "old"
}],
2815: [
{
id: "19",
name: "test",
status: "new"
},
{
id: "50",
name: "test2",
status: "old"
},
{
id: "120",
name: "test2",
status: "new"
}]
}
Need filter if status = "new" but struct must not change:
{
245: [{
id: "12",
name: "test",
status: "new"
}],
2815: [{
id: "19",
name: "test",
status: "new"
},
{
id: "120",
name: "test2",
status: "new"
}]
}
Loop over entries and create a new object with filtered values
const obj = {
245:[
{id:"12",name:"test",status:"new"},{id:"15",name:"test2",status:"old"},{id:"12",name:"test2",status:"old"}],
2815:[
{id:"19",name:"test",status:"new"},{id:"50",name:"test2",status:"old"},{id:"120",name:"test2",status:"new"}]
}
console.log(filter(obj, item => item.status === "new"))
function filter(obj, pred) {
return Object.fromEntries(Object.entries(obj).map(([name, value]) => [name, value.filter(pred)]))
}
You need to map over the object keys and then over the array elements to filter out the final result
var obj = {
245:[
{id:"12",name:"test",status:"new"},{id:"15",name:"test2",status:"old"},{id:"12",name:"test2",status:"old"}],
2815:[
{id:"19",name:"test",status:"new"},{id:"50",name:"test2",status:"old"},{id:"120",name:"test2",status:"new"}]
}
var res = Object.entries(obj).reduce((acc, [key, value]) => {
acc[key] = value.filter(item => item.status === "new");
return acc;
}, {})
console.log(res);
you can do it for this specific case like this:
const myObj = {
245:[
{id:"12",name:"test",status:"new"},
{id:"15",name:"test2",status:"old"},
{id:"12",name:"test2",status:"old"}
],
2815:[
{id:"19",name:"test",status:"new"},
{id:"50",name:"test2",status:"old"},
{id:"120",name:"test2",status:"new"}
]
};
const filteredObj = filterMyObj(myObj);
console.log(filteredObj);
function filterMyObj(myObj){
const myObjCopy = {...myObj};
for (const key in myObjCopy){
const myArrCopy = [...myObjCopy[key]];
myObjCopy[key] = myArrCopy.filter(item => item.status == "new");
}
return myObjCopy;
}
You can do it with filter :
for(let key in obj){
obj[key] = obj[key].filter(el => el.status == "new")
}

Categories

Resources