1

I am attempting to take an array of results and reduce them into a single array.

The data is:

const data = [
    { profileid: '1', points: 25, winner: true },
    { profileid: '2', points: 15, winner: false },
    { profileid: '3', points: 18, winner: false },
    { profileid: '1', points: 15, winner: true },
    { profileid: '2', points: 18, winner: false },
    { profileid: '3', points: 25, winner: false },
]

I am attempting to sum up all points by userid (I have achieved this) and also sum up the amount of times winner === true in each object

Expected Results

[
    { profileid: '1', points: 40, wins: 1 },
    { profileid: '2', points: 33, wins: 0 },
    { profileid: '3', points: 43, wins: 1 },
]

Currently I am unable to talley the sum of "true" results in each object. Additionally I am returning an object instead of an array.

Snippet

const data = [
    { profileid: '1', points: 25, winner: true },
    { profileid: '2', points: 15, winner: false },
    { profileid: '3', points: 18, winner: false },
    { profileid: '1', points: 15, winner: false },
    { profileid: '2', points: 18, winner: false },
    { profileid: '3', points: 25, winner: true },
]

const result = data.reduce((acc, cur) => ({
            ...acc,
            [cur.profileid]: {
                profileid: cur.profileid,
                points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
                wins: cur.winner
                    ? acc[cur.profile]
                        ? acc[cur.profile].wins + 1
                        : 0
                    : acc[cur.profile]
                    ? acc[cur.profile].wins
                    : 0,
            },
        }),
        []
    )
    
console.log(result)

2

2 Answers 2

2

Applying the same logic for the points can give something like:

wins: cur.winner ? ((acc[cur.profileid]?.wins || 0) + 1) : (acc[cur.profileid]?.wins || 0),

Were we start by checking if the current winner is true

  • If so, add 1 (|| 0) for the first time where wins doesn't exist
  • If not, just use acc[cur.profileid]?.wins (also a fallback if the first time is false)

const data = [
    { profileid: '1', points: 25, winner: true },
    { profileid: '2', points: 15, winner: false },
    { profileid: '3', points: 18, winner: false },
    { profileid: '1', points: 15, winner: false },
    { profileid: '2', points: 18, winner: false },
    { profileid: '3', points: 25, winner: true },
]

const result = data.reduce((acc, cur) => ({
        ...acc,
        [cur.profileid]: {
            wins: cur.winner ? ((acc[cur.profileid]?.wins || 0) + 1) : (acc[cur.profileid]?.wins || 0),
            profileid: cur.profileid,
            points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
        },
    }),
    []
)
    
console.log(result)


That said, I'd personally prefer a simple for and a single if to get a more readable code:

Please consider this example:

  • Create empty result obj
  • Loop over each obj in the data array
  • Create empty obj in data if needed
  • Bump the points and wins values

const data = [
    { profileid: '1', points: 25, winner: true },
    { profileid: '2', points: 15, winner: false },
    { profileid: '3', points: 18, winner: false },
    { profileid: '1', points: 15, winner: false },
    { profileid: '2', points: 18, winner: false },
    { profileid: '3', points: 25, winner: true },
];
const result = {};

for (let i in data) {
  
    // Create current profileId object
    if (!result[data[i].profileid]) {
        result[data[i].profileid] = {
            wins: 0,
            points: 0,
            profileid: +data[i].profileid
        };
    }

    // Bump points/wins values
    result[data[i].profileid].points += data[i].points;
    result[data[i].profileid].wins += +data[i].winner;
}

console.log(result);

Sign up to request clarification or add additional context in comments.

Comments

0

You can sum the wins the same way as you sum the points:

const data = [
    { profileid: '1', points: 25, winner: true },
    { profileid: '2', points: 15, winner: false },
    { profileid: '3', points: 18, winner: false },
    { profileid: '1', points: 15, winner: true },
    { profileid: '2', points: 18, winner: false },
    { profileid: '3', points: 25, winner: true },
]

const result = data.reduce((acc, cur) => ({
            ...acc,
            [cur.profileid]: {
                profileid: cur.profileid,
                points: cur.points + (acc[cur.profileid] ? acc[cur.profileid].points : 0),
                wins: cur.winner + (acc[cur.profileid] ? acc[cur.profileid].wins : 0)
            },
        }),
        []
    )
    
console.log(result)

You can also simplify wins like this:
wins: !!(acc[cur.profileid]?.wins) + cur.winner

In case acc[cur.profileid]?.wins returns undefined,
you can convert it to a Boolean by !! or Boolean() to avoid getting NaN

Boolean
Optional chaining (?.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.