Reservoir Sampling is the answer to a common interview question.

import spire.random.Generator.rng
import spire.algebra.Field

implicit val fieldDouble: Field[Double] = spire.implicits.DoubleAlgebra

import axle.stats._
import axle.math.arithmeticMean

Demonstrate it uniformly sampling 15 of the first 100 integers

val sample = reservoirSampleK(15, LazyList.from(1), rng).drop(100).head
// sample: List[Int] = List(
//   97,
//   95,
//   87,
//   85,
//   80,
//   73,
//   67,
//   63,
//   60,
//   59,
//   58,
//   34,
//   29,
//   27,
//   11
// )

arithmeticMean(sample.map(_.toDouble))
// res0: Double = 61.666666666666664

The mean of the sample should be in the ballpark of the mean of the entire list – 50.