Consider this:
first = %w[jane john]
last = %w[doe smith]
first.product(last)
# => [["jane", "doe"], ["jane", "smith"], ["john", "doe"], ["john", "smith"]]
You can do something like this:
first = File.readlines('name.txt').map(&:rstrip)
last = File.readlines('last.txt').map(&:rstrip)
first.product(last)
product
is one of Array's methods. Also look at permutation
and combination
.
We can use chomp
instead of rstrip
to remove a trailing new-line, which will be returned by readlines
, however chomp
only trims new-lines, whereas rstrip
will remove trailing whitespace, cleaning up the names a bit if there is any trailing whitespace. (In my experience it's more likely we'll see whitespace after text than before it, because it's easier to see when it's leading.)
Benchmarks:
require 'fruity'
FIRST_NAME = [*'a'..'z']
LAST_NAME = [*'a'..'z']
FIRST_NAME.size # => 26
LAST_NAME.size # => 26
def use_product
FIRST_NAME.product(LAST_NAME)
end
def use_loops
output = []
FIRST_NAME.each do |fn|
LAST_NAME.each do |ln|
output << [fn, ln]
end
end
output
end
result = use_product
result.size # => 676
result.first # => ["a", "a"]
result.last # => ["z", "z"]
result = use_loops
result.size # => 676
result.first # => ["a", "a"]
result.last # => ["z", "z"]
Running it results in:
compare :use_product, :use_loops
# >> Running each test 64 times. Test will take about 1 second.
# >> use_product is faster than use_loops by 50.0% ± 10.0%
If the source arrays increase in size:
require 'fruity'
FIRST_NAME = [*'a1'..'z9']
LAST_NAME = [*'a1'..'z9']
FIRST_NAME.size # => 259
LAST_NAME.size # => 259
def use_product
FIRST_NAME.product(LAST_NAME)
end
def use_loops
output = []
FIRST_NAME.each do |fn|
LAST_NAME.each do |ln|
output << [fn, ln]
end
end
output
end
result = use_product
result.size # => 67081
result.first # => ["a1", "a1"]
result.last # => ["z9", "z9"]
result = use_loops
result.size # => 67081
result.first # => ["a1", "a1"]
result.last # => ["z9", "z9"]
Running that returns:
compare :use_product, :use_loops
# >> Running each test once. Test will take about 1 second.
# >> use_product is faster than use_loops by 60.00000000000001% ± 10.0%
While we can write the algorithm without taking advantage of the built-in methods, the methods are written in C so take advantage of them to gain their added speed.
There is a time I'd use iteration of separate arrays over the built-in product
: If I had two huge lists, and pulling them into memory was prohibitive because of RAM constraints causing scalability issues, then the only way to deal with it would be nested loops. Ruby's foreach
is extremely fast, so writing code around it would be a good alternate:
File.foreach('name.txt') do |first|
File.foreach('last.txt') do |last|
full_name = first.chomp + " " + last.chomp
puts full_name
end
end