Smith numbers

var primes = Enumerator({ |callback|
    static primes = Hash()
    var p = 2
    loop {
        callback(p)
        p = (primes{p} := p.next_prime)
    }
})

func factors(remainder) {

    remainder == 1 && return([remainder])

    gather {
        primes.each { |factor|
            if (factor*factor > remainder) {
                take(remainder) if (remainder > 1)
                break
            }

            while (factor.divides(remainder)) {
                take(factor)
                break if ((remainder /= factor) == 1)
            }
        }
    }
}

func is_smith_number(n) {
    !n.is_prime && (n.sumdigits == factors(n).join.to_i.sumdigits)
}

var s = range(2, 10_000).grep { is_smith_number(_) }
say "#{s.len} Smith numbers below 10_000"
say "First 10: #{s.first(10)}"
say "Last  10: #{s.last(10)}"

Output:

376 Smith numbers below 10_000
First 10: [4, 22, 27, 58, 85, 94, 121, 166, 202, 265]
Last  10: [9843, 9849, 9861, 9880, 9895, 9924, 9942, 9968, 9975, 9985]