Dev

SMART LOTTO Dev Log #4 — Why Statistics Were Slow, and How a Dictionary Fixed It

2026-01-31·2min read
SMART LOTTO Dev Log #4 — Why Statistics Were Slow, and How a Dictionary Fixed It

Data Was There. Screen Was Sluggish.

I successfully stored all historical lottery draw data in Realm. Around 1,000 draws at first, growing past 1,200 as new draws were added.

The problem appeared on the statistics screen.

Every time it loaded, the app pulled all Realm records and ran a full iteration to count how many times each number (1–45) had appeared in 1st-prize draws. The lag was noticeable.


The Problematic Code

The naive implementation:

let allResults = realm.objects(LottoResult.self)
var frequency: [Int: Int] = [:]

for result in allResults {
    let numbers = [result.num1, result.num2, result.num3,
                   result.num4, result.num5, result.num6]
    for num in numbers {
        frequency[num, default: 0] += 1
    }
}

1,200 draws × 6 numbers = 7,200 iterations, plus the overhead of loading all 1,200 Realm objects into memory. Not enormous in absolute terms — but repeated every time the screen opened, the accumulated cost was felt.


The Fix: Pre-Compute Once, Look Up Instantly

The insight: don't compute this every time the screen opens. Compute it once and cache the result.

On app launch (or whenever new data arrives), run the full calculation once and store the result as a [Int: Int] Dictionary in memory:

var numberFrequency: [Int: Int] = [:]
let allResults = realm.objects(LottoResult.self)

for result in allResults {
    [result.num1, result.num2, result.num3,
     result.num4, result.num5, result.num6].forEach {
        numberFrequency[$0, default: 0] += 1
    }
}

After this runs once, the statistics screen doesn't touch Realm. It reads directly from numberFrequency:

let count = numberFrequency[7] ?? 0  // O(1)

Why Dictionary vs. Array

An array of 45 elements requires index-based access or a linear search. Dictionary lookup by key is O(1) regardless of size.

For 45 numbers the performance difference is small — but this lookup happens repeatedly as the chart renders, sorts, and updates. The cumulative difference is meaningful, and the code clarity is significantly better.


The Broader Lesson

This caching pattern appeared again and again in later projects: compute expensive results once, store them in a fast-access structure, reuse.

On mobile, CPU cycles are battery. Users feel an app is draining their phone before they consciously notice sluggishness. Performance optimization isn't just about speed — it's about how the app feels to live with.

Next: the two user reviews that added two new features.