JavascriptIntermediate
Array Statistics
Build a tool that calculates statistics — sum, average, min, max, median — from a list of numbers entered by the user.
Array Statistics
Problem
Build a tool where the user enters a list of numbers separated by commas, and the app calculates and displays statistics — sum, average, minimum, maximum, range, and median.
Input: 4, 8, 15, 16, 23, 42
Output:
Count: 6
Sum: 108
Average: 18
Min: 4
Max: 42
Range: 38
Median: 15.5
Input: 7
Output:
Count: 1 Sum: 7 Average: 7 Min: 7 Max: 7 Range: 0 Median: 7
Input: (empty)
Output: Please enter at least one numberLogic
- Select the input, button, and result display
- Read and parse the comma-separated numbers
- Validate that all entries are valid numbers
- Calculate sum using
reduce - Calculate average from sum and count
- Find min and max using
Math.minandMath.max - Calculate range as
max - min - Calculate median — sort the array, find the middle value(s)
- Display all stats in a grid
Flow
HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Array Statistics</title>
<style>
body {
font-family: sans-serif;
max-width: 480px;
margin: 60px auto;
padding: 0 20px;
}
.input-row {
display: flex;
gap: 10px;
margin-bottom: 16px;
}
.input-row input {
flex: 1;
padding: 12px;
font-size: 1rem;
border: 2px solid #ccc;
border-radius: 8px;
outline: none;
box-sizing: border-box;
}
.input-row input:focus {
border-color: #555;
}
.input-row button {
padding: 12px 20px;
font-size: 1rem;
font-weight: 600;
background: #111;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
}
.input-row button:hover {
opacity: 0.85;
}
#error {
color: #c0392b;
font-size: 0.9rem;
margin-bottom: 12px;
display: none;
}
/* stats grid — 2 columns */
#stats {
display: none;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.stat-card {
background: #f5f5f5;
border-radius: 8px;
padding: 14px 16px;
}
.stat-card .label {
font-size: 0.8rem;
color: #888;
margin-bottom: 4px;
}
.stat-card .value {
font-size: 1.4rem;
font-weight: 700;
color: #111;
}
</style>
</head>
<body>
<h1>Array Statistics</h1>
<div class="input-row">
<input
type="text"
id="numbers-input"
placeholder="e.g. 4, 8, 15, 16, 23, 42"
/>
<button id="calculate-btn">Calculate</button>
</div>
<div id="error"></div>
<!-- stat cards rendered here -->
<div id="stats">
<div class="stat-card">
<div class="label">Count</div>
<div class="value" id="stat-count">-</div>
</div>
<div class="stat-card">
<div class="label">Sum</div>
<div class="value" id="stat-sum">-</div>
</div>
<div class="stat-card">
<div class="label">Average</div>
<div class="value" id="stat-average">-</div>
</div>
<div class="stat-card">
<div class="label">Median</div>
<div class="value" id="stat-median">-</div>
</div>
<div class="stat-card">
<div class="label">Min</div>
<div class="value" id="stat-min">-</div>
</div>
<div class="stat-card">
<div class="label">Max</div>
<div class="value" id="stat-max">-</div>
</div>
<div class="stat-card">
<div class="label">Range</div>
<div class="value" id="stat-range">-</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Solution
// Step 1 — select elements
const numbersInput = document.querySelector("#numbers-input");
const calculateBtn = document.querySelector("#calculate-btn");
const error = document.querySelector("#error");
const stats = document.querySelector("#stats");
// Step 2 — listen for click and Enter key
calculateBtn.addEventListener("click", calculateStats);
numbersInput.addEventListener("keydown", (e) => {
if (e.key === "Enter") calculateStats();
});
function calculateStats() {
const value = numbersInput.value.trim();
// Step 3 — handle empty input
if (!value) {
showError("Please enter at least one number.");
return;
}
// Step 4 — split, trim, and filter out empty entries
const parts = value
.split(",")
.map((item) => item.trim())
.filter((item) => item !== "");
// Step 5 — validate all entries are numbers
const hasInvalid = parts.some((item) => isNaN(Number(item)));
if (hasInvalid) {
showError("Please enter valid numbers only.");
return;
}
// Step 6 — convert to numbers
const numbers = parts.map(Number);
// Step 7 — calculate sum using reduce
// reduce starts with 0 and adds each number to the running total
const sum = numbers.reduce((total, n) => total + n, 0);
// Step 8 — calculate average
const average = sum / numbers.length;
// Step 9 — find min and max
// spread the array as individual arguments to Math.min/max
const min = Math.min(...numbers);
const max = Math.max(...numbers);
// Step 10 — calculate range
const range = max - min;
// Step 11 — calculate median
const median = calculateMedian(numbers);
// Step 12 — display all stats
showStats({
count: numbers.length,
sum,
average,
min,
max,
range,
median
});
}
// Step 13 — median calculation function
function calculateMedian(numbers) {
// create a sorted copy — do not mutate the original array
// [...numbers] spreads into a new array before sorting
const sorted = [...numbers].sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
// if length is odd — return the exact middle value
// if length is even — return the average of the two middle values
if (sorted.length % 2 !== 0) {
return sorted[middle];
}
return (sorted[middle - 1] + sorted[middle]) / 2;
}
// helper — formats a number to at most 2 decimal places
// removes trailing zeros — 18.00 becomes 18, 18.50 stays 18.5
function formatNumber(num) {
return Math.round(num * 100) / 100;
}
// helper — displays the calculated stats
function showStats(data) {
error.style.display = "none";
stats.style.display = "grid";
document.querySelector("#stat-count").textContent = data.count;
document.querySelector("#stat-sum").textContent = formatNumber(data.sum);
document.querySelector("#stat-average").textContent = formatNumber(data.average);
document.querySelector("#stat-median").textContent = formatNumber(data.median);
document.querySelector("#stat-min").textContent = data.min;
document.querySelector("#stat-max").textContent = data.max;
document.querySelector("#stat-range").textContent = data.range;
}
function showError(message) {
error.textContent = message;
error.style.display = "block";
stats.style.display = "none";
}Code Execution
Trace through input "4, 8, 15, 16, 23, 42":
| Step | Code | Result |
|---|---|---|
| Split and clean | ["4","8","15","16","23","42"] | |
| Convert | .map(Number) | [4, 8, 15, 16, 23, 42] |
| Sum | reduce((t,n) => t+n, 0) | 108 |
| Average | 108 / 6 | 18 |
| Min | Math.min(...numbers) | 4 |
| Max | Math.max(...numbers) | 42 |
| Range | 42 - 4 | 38 |
Median trace for [4, 8, 15, 16, 23, 42] (6 items — even):
| Step | Code | Result |
|---|---|---|
| Sorted | [4, 8, 15, 16, 23, 42] (already sorted) | same |
middle | Math.floor(6 / 2) | 3 |
| Even check | 6 % 2 !== 0 | false |
| Median | (sorted[2] + sorted[3]) / 2 → (15 + 16) / 2 | 15.5 |
Median trace for [7] (1 item — odd):
| Step | Code | Result |
|---|---|---|
| Sorted | [7] | same |
middle | Math.floor(1 / 2) | 0 |
| Odd check | 1 % 2 !== 0 | true |
| Median | sorted[0] | 7 |
Output
Input: 4, 8, 15, 16, 23, 42
→ Count: 6 Sum: 108 Average: 18 Median: 15.5 Min: 4 Max: 42 Range: 38
Input: 7
→ Count: 1 Sum: 7 Average: 7 Median: 7 Min: 7 Max: 7 Range: 0
Input: (empty)
→ Please enter at least one number