Reputation: 51
I have an array of objects in javascript that i want to reduce. See code below. message with 6 or more digits is verified, fewer is unverified. I group them by group.
const myArray = [
{ group: 'groupA', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupC', message: 'Text without a number', sl: '1B' },
{ group: 'groupD', message: 'Text with a number Tick0127866', sl: '1B' },
{ group: 'groupC', message: 'Text without a number', sl: '1A' }
];
output = myArray.reduce((acc, line) => {
let yes = 0;
let no = 0;
line.message.match(/\d{6,}/) ? yes++ : no++;
acc[line.group] = acc[line.group] || {};
acc[line.group].verified = (acc[line.group].verified || 0) + yes;
acc[line.group].unverified = (acc[line.group].unverified || 0) + no;
return acc;
}, {});
console.log('output', output);
However I would like the output to also be an array of objects like so:
[
{ group: 'groupA', verified: 2, unverified: 1 },
{ group: 'groupB', verified: 1, unverified: 1 },
{ group: 'groupC', verified: 0, unverified: 2 },
{ group: 'groupD', verified: 1, unverified: 0 }
]
How would I do this?
Upvotes: 2
Views: 1133
Reputation: 5144
I couldn't resist refactoring your code a little. That said. what I have done:
[]
)verified
or unverified
depending whether your test failsconst myArray = [
{ group: "groupA", message: "Text without a number", sl: "1A" },
{ group: "groupA", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupB", message: "Text without a number", sl: "1A" },
{ group: "groupA", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupB", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupC", message: "Text without a number", sl: "1B" },
{ group: "groupD", message: "Text with a number Tick0127866", sl: "1B" },
{ group: "groupC", message: "Text without a number", sl: "1A" }
];
output = myArray.reduce((acc, line) => {
if( acc.findIndex(e => e.group === line.group) === -1 ) {
acc.push({
group: line.group,
verified: 0,
unverified: 0
});
}
let group = acc.find(e => e.group === line.group);
if( line.message.match(/\d{6,}/) )
group.verified++;
else
group.unverified++;
return acc;
}, []);
console.log(output);
Upvotes: 2
Reputation: 5853
Use reduce in combination with regex testing like this -
const myArray = [{
group: 'groupA',
message: 'Text without a number',
sl: '1A'
},
{
group: 'groupA',
message: 'Text with a number WO5467829',
sl: '1A'
},
{
group: 'groupB',
message: 'Text without a number',
sl: '1A'
},
{
group: 'groupA',
message: 'Text with a number WO5467829',
sl: '1A'
},
{
group: 'groupB',
message: 'Text with a number WO5467829',
sl: '1A'
},
{
group: 'groupC',
message: 'Text without a number',
sl: '1B'
},
{
group: 'groupD',
message: 'Text with a number Tick0127866',
sl: '1B'
},
{
group: 'groupC',
message: 'Text without a number',
sl: '1A'
}
];
const numberRegex = /[0-9]{6}/;
const res = Object.values(myArray.reduce((acc, curr) => {
const { group, message } = curr;
const isPhoneVerified = numberRegex.test(message);
if (!acc[group] && isPhoneVerified) {
acc[group] = { group: group, verified: 1, unverified: 0 };
} else if (!acc[group] && !isPhoneVerified) {
acc[group] = { group: group, verified: 0, unverified: 1 };
} else if (acc[group] && isPhoneVerified) {
acc[group].verified += 1;
} else if (acc[group] && !isPhoneVerified) {
acc[group].unverified += 1;
}
return acc;
}, {}));
console.log(res);
Upvotes: 1
Reputation: 36594
You can use map()
on Object.entries
. I also refactored your code in reduce
method
const myArray = [
{ group: 'groupA', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupC', message: 'Text without a number', sl: '1B' },
{ group: 'groupD', message: 'Text with a number Tick0127866', sl: '1B' },
{ group: 'groupC', message: 'Text without a number', sl: '1A' }
];
let output = myArray.reduce((acc, line) => {
acc[line.group] = acc[line.group] || {verified: 0, unverified: 0};
if(line.message.match(/\d{6,}/)){
acc[line.group].verified++
}
else{
acc[line.group].unverified++
}
return acc;
}, {});
output = Object.entries(output).map(([k, v]) => ({group: k, ...v}))
console.log('output', output);
Upvotes: 1
Reputation: 17664
Use an array as the initial value of your accumulator and inside .reduce
, use findIndex
to check for the current group, if found, update verified
and unverified
values, otherwise, insert a new one :
const myArray = [
{ group: "groupA", message: "Text without a number", sl: "1A" },
{ group: "groupA", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupB", message: "Text without a number", sl: "1A" },
{ group: "groupA", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupB", message: "Text with a number WO5467829", sl: "1A" },
{ group: "groupC", message: "Text without a number", sl: "1B" },
{ group: "groupD", message: "Text with a number Tick0127866", sl: "1B" },
{ group: "groupC", message: "Text without a number", sl: "1A" }
];
output = myArray.reduce((acc, line) => {
let yes = 0;
let no = 0;
line.message.match(/\d{6,}/) ? yes++ : no++;
// check if you have the group in the accumulator
const ndx = acc.findIndex(e => e.group === line.group);
// if you have it, manipulate verified and unverified
if (ndx > -1) {
acc[ndx].verified = (acc[ndx].verified || 0) + yes;
acc[ndx].unverified = (acc[ndx].unverified || 0) + no;
} else {
// insert a new entry instead
acc.push({
group: line.group,
verified: yes,
unverified: no
});
}
return acc;
}, []); // use an array as the initial value of the accumulator
console.log(output);
Upvotes: 3
Reputation: 22925
You can simply extend your solution/output to get the actual required output using Object.entries()
or Object.keys()
. I am going to use Object.entries()
const myArray = [
{ group: 'groupA', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupC', message: 'Text without a number', sl: '1B' },
{ group: 'groupD', message: 'Text with a number Tick0127866', sl: '1B' },
{ group: 'groupC', message: 'Text without a number', sl: '1A' }
];
output = myArray.reduce((acc, line) => {
let yes = 0;
let no = 0;
line.message.match(/\d{6,}/) ? yes++ : no++;
acc[line.group] = acc[line.group] || {};
acc[line.group].verified = (acc[line.group].verified || 0) + yes;
acc[line.group].unverified = (acc[line.group].unverified || 0) + no;
return acc;
}, {});
console.log('output', output);
const actualOutput = Object.entries(output).map(([group, value]) => ({group, ...value }));
console.log(actualOutput);
Upvotes: 2
Reputation: 1570
Put the group
prop in your acc.
Then use Object.values
function to return the values of an object.
const myArray = [
{ group: 'groupA', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text without a number', sl: '1A' },
{ group: 'groupA', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupB', message: 'Text with a number WO5467829', sl: '1A' },
{ group: 'groupC', message: 'Text without a number', sl: '1B' },
{ group: 'groupD', message: 'Text with a number Tick0127866', sl: '1B' },
{ group: 'groupC', message: 'Text without a number', sl: '1A' }
];
output = myArray.reduce((acc, line) => {
let yes = 0;
let no = 0;
line.message.match(/\d{6,}/) ? yes++ : no++;
acc[line.group] = acc[line.group] || {};
acc[line.group].group = line.group;
acc[line.group].verified = (acc[line.group].verified || 0) + yes;
acc[line.group].unverified = (acc[line.group].unverified || 0) + no;
return acc;
}, {});
console.log('output', Object.values(output));
Upvotes: 1