Hoppa till huvudinnehåll

Summera tal i en array med JavaScript

· 6 min att läsa
Filip Tammergård
Programmerare på Frilans Finans

Det finns flera sätt att räkna ut summan av tal i en array med JavaScript. De olika sätten skiljer sig framför allt i hur lättlästa de är – och lättläst kod är lättare att underhålla och lättare för andra att förstå och bygga vidare på.

TL;DR​

  • Det finns många sätt att summera tal i en array, men flera sätt är svårlästa och onödigt krångliga.
  • Det bästa sättet är med hjälp av den inbyggda funktionen reduce – eller den nyare Math.sumPrecise om du kan förlita dig på att den finns tillgänglig.

Summera tal i en array​

I kommande exempel utgår jag från den här arrayen med slumpmässiga tal:

const numbers = [20, 38, 23, 1, 39, 71]

Alternativ 1: manuell summering (ett uselt alternativ)​

Det går att göra summeringen endast med hjälp av addition, på det här viset:

const sum =
numbers[0] + numbers[1] + numbers[2] + numbers[3] + numbers[4] + numbers[5]

// sum = 192

Det här alternativet är uselt eftersom det förutsätter vetskap om hur många tal som finns i arrayen. Om ett tal skulle läggas till i arrayen skulle summan bli fel.

Alternativ 2: for-loop (ett dåligt alternativ)​

Historiskt har summeringar i JavaScript gjorts genom att göra en for-loop på det här sättet:

let sum = 0

for (let i = 0; i < numbers.length; i++) {
sum += numbers[i]
}

// sum = 192

Det är fortfarande ett otympligt sätt att summera på. Stilen är imperativ – du måste själv styra hur loopen körs – och det krävs en indexvariabel som i vars enda uppgift är att hålla koll på position. Sådana variabler kan och bör oftast undvikas.

Alternativ 3: forEach-loop (ett okej alternativ)​

forEach läser mer naturligt än en for-loop, men kräver fortfarande att man deklarerar let sum = 0 och muterar den variabeln vid varje iteration:

let sum = 0

numbers.forEach((number) => (sum += number))

// sum = 192

forEach är en higher order function som kör en callback för varje element i arrayen. Den tar bort indexvariabeln men inte muteringen.

Alternativ 4: reduce (det bästa alternativet)​

Ytterligare lite snyggare är den inbyggda funktionen reduce. Den kan användas så här:

const sum = numbers.reduce((acc, number) => acc + number, 0)

// sum = 192

Funktionen reduce tar in en funktion med parametrarna acc och number, som representerar det ackumulerade värdet respektive det nuvarande värdet i arrayen numbers. Till höger om pilen definieras vad som ska göras med värdena. I första loop-varvet är värdet av acc 0 (startvärdet som definieras i andra parametern) och number är 20. Därefter sparas resultatet av acc + number till acc i nästa loop-varv.

Summera tal i mer komplexa arrayer​

I många fall är arrayerna som innehåller tal som ska summeras lite mer komplexa än det tidigare exemplet. Låt oss utgå från den här arrayen som innehåller information om alla rum i en lägenhet:

const rooms = [
{ name: "Living room", isRenovated: true, area: 31 },
{ name: "Kitchen", isRenovated: false, area: 15 },
{ name: "Bedroom", isRenovated: false, area: 21 },
{ name: "Bathroom", isRenovated: true, area: 13 },
{ name: "Hall", isRenovated: false, area: 9 },
]

Låt säga att vi vill beräkna arean i hela lägenheten.

Alternativ 1: Omforma arrayen så att den blir enkel innan summering görs​

Använd map för att förvandla varje rum till bara dess area, och summera sedan den resulterande arrayen av tal.

const totalArea = rooms
.map((room) => room.area)
.reduce((acc, area) => acc + area, 0)

// totalArea = 89

Alternativ 2: Plocka ut arean ur objekten direkt under summeringen​

Med den andra strategin används reduce för att plocka ut arean i objekten direkt:

const totalArea = rooms.reduce((acc, room) => acc + room.area, 0)

// totalArea = 89

Av dessa tycker jag att alternativ 2 är snyggast, eftersom den både är mest kompakt och mest lättläst.

Summera med filtrering​

För att göra det lite mer komplicerat kanske vi vill veta den totala arean av de rum som inte är renoverade.

Alternativ 1: Filtrera, map:a, summera​

Använd filter för att behålla bara de rum som inte är renoverade, och omforma och summera sedan som tidigare.

const totalAreaOfNotRenovatedRooms = rooms
.filter((room) => !room.isRenovated)
.map((room) => room.area)
.reduce((acc, area) => acc + area, 0)

// totalAreaOfNotRenovatedRooms = 45

Alternativ 2: Filtrera, plocka ut arean direkt under summeringen​

Slipp mellansteget med map och plocka ut arean direkt inuti reduce.

const totalAreaOfNotRenovatedRooms = rooms
.filter((room) => !room.isRenovated)
.reduce((acc, room) => acc + room.area, 0)

// totalAreaOfNotRenovatedRooms = 45

Alternativ 3: Filtrera med if-sats inuti reduce​

Hoppa över det separata filter-anropet och grena inuti reduceraren med en if-sats för att avgöra om ett rums area ska adderas.

const totalAreaOfNotRenovatedRooms = rooms.reduce((acc, room) => {
if (!room.isRenovated) return acc + room.area
return acc
}, 0)

// totalAreaOfNotRenovatedRooms = 45

Alternativ 4: Filtrera med ternary operator i reduce​

Samma logik kan uttryckas mer kompakt med en ternary operator.

const totalAreaOfNotRenovatedRooms = rooms.reduce(
(acc, room) => (room.isRenovated ? acc : acc + room.area),
0,
)

// totalAreaOfNotRenovatedRooms = 45

Jag tycker att alternativ 2 är bäst i det här fallet. Det går nästan att läsa koden som vanlig text och förstå vad som händer:

Filtrera först fram rummen som inte är renoverade, summera sedan arean i varje rum.

Bättre alternativ​

JavaScript har numera en inbyggd statisk metod för precis det här: Math.sumPrecise. Den tar en iterable av tal och returnerar summan utan flyttalsprecisionsproblem:

const sum = Math.sumPrecise([20, 38, 23, 1, 39, 71])

// sum = 192

För lägenhetsexemplet kombinerar du den med map:

const totalArea = Math.sumPrecise(rooms.map((room) => room.area))

// totalArea = 89

Math.sumPrecise är ett relativt nytt tillägg, så stödet varierar fortfarande mellan miljöer – kolla Can I use för aktuellt status. Där den inte finns är reduce fortfarande ett bra val.

Så där, nu kan du allt om att summera tal i en array med JavaScript!

Referenser​