'Sum of all values from a dynamic key in object array

I'm trying to sum all similar keys in an object array. Each object will have similar keys but each array may not have similar object keys. I was thinking of storing the keys in another array and looping over that but not sure the best way.

Scorecard output example

Scorecard1 input example:

let scorecard1 = [
    {
        "Hole": 1,
        "Par": 4,
        "Blue": 368,
        "White": 349,
        "Handicap": 16
    },
    {
        "Hole": 2,
        "Par": 4,
        "Blue": 316,
        "White": 305,
        "Handicap": 14
    },
    {
        "Hole": 3,
        "Par": 3,
        "Blue": 169,
        "White": 158,
        "Handicap": 10
    },
    {
        "Hole": 4,
        "Par": 4,
        "Blue": 373,
        "White": 351,
        "Handicap": 12
    },
    {
        "Hole": 5,
        "Par": 4,
        "Blue": 352,
        "White": 348,
        "Handicap": 6
    },
    {
        "Hole": 6,
        "Par": 5,
        "Blue": 493,
        "White": 485,
        "Handicap": 8
    },
    {
        "Hole": 7,
        "Par": 4,
        "Blue": 367,
        "White": 356,
        "Handicap": 18
    },
    {
        "Hole": 8,
        "Par": 3,
        "Blue": 193,
        "White": 176,
        "Handicap": 4
    },
    {
        "Hole": 9,
        "Par": 5,
        "Blue": 562,
        "White": 540,
        "Handicap": 2
    },
    {
        "Hole": 10,
        "Par": 4,
        "Blue": 384,
        "White": 369,
        "Handicap": 15
    },
    {
        "Hole": 11,
        "Par": 4,
        "Blue": 311,
        "White": 292,
        "Handicap": 11
    },
    {
        "Hole": 12,
        "Par": 4,
        "Blue": 421,
        "White": 411,
        "Handicap": 5
    },
    {
        "Hole": 13,
        "Par": 3,
        "Blue": 155,
        "White": 148,
        "Handicap": 17
    },
    {
        "Hole": 14,
        "Par": 5,
        "Blue": 492,
        "White": 483,
        "Handicap": 7
    },
    {
        "Hole": 15,
        "Par": 4,
        "Blue": 425,
        "White": 409,
        "Handicap": 1
    },
    {
        "Hole": 16,
        "Par": 5,
        "Blue": 505,
        "White": 479,
        "Handicap": 13
    },
    {
        "Hole": 17,
        "Par": 3,
        "Blue": 182,
        "White": 166,
        "Handicap": 9
    },
    {
        "Hole": 18,
        "Par": 4,
        "Blue": 437,
        "White": 427,
        "Handicap": 3
    }
]

Scorecard2 input example:

let scorecard2 = [
    {
        "Hole": 1,
        "Par": 4,
        "Blue": 372,
        "White": 0,
        "Red_Intermediate": 301,
        "gold": 0,
        "Handicap": 10
    },
    {
        "Hole": 2,
        "Par": 4,
        "Blue": 394,
        "White": 0,
        "Red_Intermediate": 370,
        "gold": 0,
        "Handicap": 4
    },
    {
        "Hole": 3,
        "Par": 4,
        "Blue": 369,
        "White": 0,
        "Red_Intermediate": 248,
        "gold": 0,
        "Handicap": 5
    },
    {
        "Hole": 4,
        "Par": 4,
        "Blue": 361,
        "White": 0,
        "Red_Intermediate": 275,
        "gold": 0,
        "Handicap": 18
    },
    {
        "Hole": 5,
        "Par": 4,
        "Blue": 297,
        "White": 0,
        "Red_Intermediate": 260,
        "gold": 0,
        "Handicap": 16
    },
    {
        "Hole": 6,
        "Par": 3,
        "Blue": 188,
        "White": 0,
        "Red_Intermediate": 167,
        "gold": 0,
        "Handicap": 13
    },
    {
        "Hole": 7,
        "Par": 4,
        "Blue": 342,
        "White": 0,
        "Red_Intermediate": 245,
        "gold": 0,
        "Handicap": 12
    },
    {
        "Hole": 8,
        "Par": 3,
        "Blue": 184,
        "White": 0,
        "Red_Intermediate": 99,
        "gold": 0,
        "Handicap": 17
    },
    {
        "Hole": 9,
        "Par": 5,
        "Blue": 570,
        "White": 0,
        "Red_Intermediate": 452,
        "gold": 0,
        "Handicap": 1
    },
    {
        "Hole": 10,
        "Par": 4,
        "Blue": 367,
        "White": 0,
        "Red_Intermediate": 303,
        "gold": 0,
        "Handicap": 7
    },
    {
        "Hole": 11,
        "Par": 5,
        "Blue": 481,
        "White": 0,
        "Red_Intermediate": 443,
        "gold": 0,
        "Handicap": 3
    },
    {
        "Hole": 12,
        "Par": 4,
        "Blue": 352,
        "White": 0,
        "Red_Intermediate": 311,
        "gold": 0,
        "Handicap": 11
    },
    {
        "Hole": 13,
        "Par": 4,
        "Blue": 313,
        "White": 0,
        "Red_Intermediate": 264,
        "gold": 0,
        "Handicap": 15
    },
    {
        "Hole": 14,
        "Par": 4,
        "Blue": 323,
        "White": 0,
        "Red_Intermediate": 299,
        "gold": 0,
        "Handicap": 14
    },
    {
        "Hole": 15,
        "Par": 3,
        "Blue": 186,
        "White": 0,
        "Red_Intermediate": 156,
        "gold": 0,
        "Handicap": 6
    },
    {
        "Hole": 16,
        "Par": 4,
        "Blue": 439,
        "White": 0,
        "Red_Intermediate": 278,
        "gold": 0,
        "Handicap": 2
    },
    {
        "Hole": 17,
        "Par": 4,
        "Blue": 379,
        "White": 0,
        "Red_Intermediate": 333,
        "gold": 0,
        "Handicap": 9
    },
    {
        "Hole": 18,
        "Par": 4,
        "Blue": 318,
        "White": 0,
        "Red_Intermediate": 255,
        "gold": 0,
        "Handicap": 8
    }
]

Scorecard.jsx

function Scorecard({ scorecard }) {

let nineHoles = scorecard.length === 9
let frontScorecard = []
let backScorecard = []
let splitScorecard = () => {
    if (!nineHoles) {
        var splitScorecard = Math.ceil(scorecard.length / 2)
        frontScorecard = scorecard.slice(0, splitScorecard)
        backScorecard = scorecard.slice(splitScorecard, scorecard.length)
    } else {
        frontScorecard = scorecard
    }
}

splitScorecard()

let fillScorecard = (holes) => {
    return (holes.map((x, i) => (
        <div key={i}>
            {Object.values(x).map((val, i) => (
                <div className="scorecard-block" key={i}>{val}</div>
            ))}
        </div>
    )))
}

let cardStart =
    <div>{Object.keys(scorecard[0]).map((x) => (
        <div className="scorecard-block">
            {x}
        </div>
    ))}
    </div>

let cardEndFront = <div>
    {nineHoles ?
        <>
            <div className="scorecard-block">
                In
            </div>
            <div className="scorecard-block">
                Total
            </div>
        </>
        :
        <div className="scorecard-block">
            Out
        </div>
    }
    {Object.keys(scorecard).slice(0, 4).map((x) => (
        <div className="scorecard-block">
            {x}
        </div>
    ))}
</div>

let cardEndBack = <>
    <div>
        <div className="scorecard-block">In</div>
        {Object.keys(scorecard).slice(0, 4).map((x) => (
            <div className="scorecard-block">
                {x}
            </div>
        ))}
    </div>

    <div>
        <div className="scorecard-block">Total</div>
        {Object.keys(scorecard).slice(0, 4).map((x) => (
            <div className="scorecard-block">
                {x}
            </div>
        ))}
    </div>
</>

return (
    <>
        <div className="frontnine-data-container">
            {cardStart}
            {fillScorecard(frontScorecard)}
            {cardEndFront}
        </div>
        <br />
        {!nineHoles && <div className="backnine-data-container">
            {cardStart}
            {fillScorecard(backScorecard)}
            {cardEndBack}
        </div>}
    </>
)


Solution 1:[1]

You can use the reduce() method coupled with Object.entries() as follows:

let scorecard1 = [ { "Hole": 1, "Par": 4, "Blue": 368, "White": 349, "Handicap": 16 }, { "Hole": 2, "Par": 4, "Blue": 316, "White": 305, "Handicap": 14 },  { "Hole": 3, "Par": 3, "Blue": 169, "White": 158, "Handicap": 10 }, { "Hole": 4, "Par": 4, "Blue": 373, "White": 351, "Handicap": 12 }, { "Hole": 5, "Par": 4, "Blue": 352, "White": 348, "Handicap": 6 }, { "Hole": 6, "Par": 5, "Blue": 493, "White": 485, "Handicap": 8 }, { "Hole": 7, "Par": 4, "Blue": 367, "White": 356, "Handicap": 18 }, { "Hole": 8, "Par": 3, "Blue": 193, "White": 176, "Handicap": 4 }, { "Hole": 9, "Par": 5, "Blue": 562, "White": 540, "Handicap": 2 }, { "Hole": 10, "Par": 4, "Blue": 384, "White": 369, "Handicap": 15 }, { "Hole": 11, "Par": 4, "Blue": 311, "White": 292, "Handicap": 11 }, { "Hole": 12, "Par": 4, "Blue": 421, "White": 411, "Handicap": 5 }, { "Hole": 13, "Par": 3, "Blue": 155, "White": 148, "Handicap": 17 }, { "Hole": 14, "Par": 5, "Blue": 492, "White": 483, "Handicap": 7 }, { "Hole": 15, "Par": 4, "Blue": 425, "White": 409, "Handicap": 1 }, { "Hole": 16, "Par": 5, "Blue": 505, "White": 479, "Handicap": 13 }, { "Hole": 17, "Par": 3, "Blue": 182, "White": 166, "Handicap": 9 }, {"Hole": 18,"Par": 4,"Blue": 437,"White": 427, "Handicap": 3 }];

let scorecard2 = [ { "Hole": 1, "Par": 4, "Blue": 372, "White": 0, "Red_Intermediate": 301, "gold": 0, "Handicap": 10 }, { "Hole": 2, "Par": 4, "Blue": 394, "White": 0, "Red_Intermediate": 370, "gold": 0, "Handicap": 4 }, { "Hole": 3, "Par": 4, "Blue": 369, "White": 0, "Red_Intermediate": 248, "gold": 0, "Handicap": 5 }, { "Hole": 4, "Par": 4, "Blue": 361, "White": 0, "Red_Intermediate": 275, "gold": 0, "Handicap": 18 }, { "Hole": 5, "Par": 4, "Blue": 297, "White": 0, "Red_Intermediate": 260, "gold": 0, "Handicap": 16 }, { "Hole": 6, "Par": 3, "Blue": 188, "White": 0, "Red_Intermediate": 167, "gold": 0, "Handicap": 13 }, { "Hole": 7, "Par": 4, "Blue": 342, "White": 0, "Red_Intermediate": 245, "gold": 0, "Handicap": 12 }, { "Hole": 8, "Par": 3, "Blue": 184, "White": 0, "Red_Intermediate": 99, "gold": 0, "Handicap": 17 }, { "Hole": 9, "Par": 5, "Blue": 570, "White": 0, "Red_Intermediate": 452, "gold": 0, "Handicap": 1 }, { "Hole": 10, "Par": 4, "Blue": 367, "White": 0, "Red_Intermediate": 303, "gold": 0, "Handicap": 7 }, { "Hole": 11, "Par": 5, "Blue": 481, "White": 0, "Red_Intermediate": 443, "gold": 0, "Handicap": 3 }, { "Hole": 12, "Par": 4, "Blue": 352, "White": 0, "Red_Intermediate": 311, "gold": 0, "Handicap": 11 }, { "Hole": 13, "Par": 4, "Blue": 313, "White": 0, "Red_Intermediate": 264, "gold": 0, "Handicap": 15 }, { "Hole": 14, "Par": 4, "Blue": 323, "White": 0, "Red_Intermediate": 299, "gold": 0, "Handicap": 14 }, { "Hole": 15, "Par": 3, "Blue": 186, "White": 0, "Red_Intermediate": 156, "gold": 0, "Handicap": 6 }, { "Hole": 16, "Par": 4, "Blue": 439, "White": 0, "Red_Intermediate": 278, "gold": 0, "Handicap": 2 }, { "Hole": 17, "Par": 4, "Blue": 379, "White": 0, "Red_Intermediate": 333, "gold": 0, "Handicap": 9 }, { "Hole": 18, "Par": 4, "Blue": 318, "White": 0, "Red_Intermediate": 255, "gold": 0, "Handicap": 8 }];

const totals = scoreboard => scoreboard.reduce(
    (prev,cur,i) => i === 0 ? cur : 
    Object.entries(cur).reduce(
        (ac,[key,value]) => ({...ac,[key]:value+prev[key]}), {}
    ),{}
);

console.log( totals( scorecard1 ) );

console.log( totals( scorecard2 ) );

console.log( [scorecard1, scorecard2].map(s => totals( s )) );

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1