Skip to content

Instantly share code, notes, and snippets.

@baweaver
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save baweaver/11163861 to your computer and use it in GitHub Desktop.
Save baweaver/11163861 to your computer and use it in GitHub Desktop.
# Patch numbers to have a prime? method
class Fixnum
def prime?
([1,2].include?(self) || !(2..Math.sqrt(self).ceil).find { |x| self % x == 0 })
end
end
# Basic implementation - 42 minutes
(1..1_000_000).select { |n|
n.to_s
.chars
.permutation
.flat_map(&:join)
.map(&:to_i)
.all?(&:prime?)
}.count
# With caching - 38 minutes
cache = {}
(1..1_000_000).select { |n|
n.to_s
.chars
.permutation
.flat_map(&:join)
.map(&:to_i)
.all? { |x| cache.fetch(x) { |y| cache[x] = y.prime? } }
}.count
# A lot faster implementation: 42 seconds
(1..1_000_000).select { |n|
n == 2 ||
((s = n.to_s.chars) & %w(0 2 4 6 8)).count == 0 &&
s.permutation
.flat_map(&:join)
.map(&:to_i)
.all?(&:prime?)
}.count
# Ahaha, left off 5, down to 18 seconds:
(1..1_000_000).select { |n|
n == 2 ||
((s = n.to_s.chars) & %w(0 2 4 5 6 8)).count == 0 &&
s.permutation
.flat_map(&:join)
.map(&:to_i)
.all?(&:prime?)
}.count
# Implementing pipeable, 1 second hit but I think it's more readable.
# https://github.com/baweaver/pipeable
(1..1_000_000).select { |n|
n == 2 ||
n.to_s.chars.pipe { |c|
(c & %w(0 2 4 5 6 8)).count == 0 &&
c.permutation
.flat_map(&:join)
.map(&:to_i)
.all?(&:prime?)
}
}.count
@baweaver
Copy link
Author

To explain why the devil I do the to_s conversions:

We're transforming the number into a string, getting its' characters into an array, getting all permutations of those characters, flat mapping the results ( [[1,2,3],[2,3,1]] becomes [123, 231]), mapping those strings back to integers, and checking if all of them are prime.

The caching method uses a hash fetch to remember which values have already been checked, such that 11 won't get hit twice on computation. This becomes more of a gain as you get into higher orders of numbers though.

@baweaver
Copy link
Author

I really really REALLY need to redo this thing in Haskell. The Ruby version tanks out pretty fast.

@baweaver
Copy link
Author

This solution owns the other one in terms of speed.

(1..1_000_000).select { |n| 
  n == 2 || 
  ((s = n.to_s.chars) & %w(0 2 4 6 8)).count == 0 &&
  s.permutation
    .flat_map(&:join)
    .map(&:to_i)
    .all?(&:prime?)
}.count

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment