Ruby #select, but only select a certain number - ruby

Whats the best way in Ruby to do something like my_array.select(n){ |elem| ... }, where the n means "I only want n elements returned, and stop evaluating after that number is reached"?

This should do the trick:
my_array.select(n) { |elem| elem.meets_condition? }.take(n)
However, this will still evaluate all items.
If you have a lazy enumerator, you could do this in a more efficient manner.
https://github.com/ruby/ruby/pull/100 shows an attempt at enabling this feature.

You can easily implement lazy_select:
module Enumerable
def lazy_select
Enumerator.new do |yielder|
each do |e|
yielder.yield(e) if yield(e)
end
end
end
end
Then things like
(1..10000000000).to_enum.lazy_select{|e| e % 3 == 0}.take(3)
# => [3, 6, 9]
execute instantly.

Looks like there's no avoiding a traditional loop if you're using stock 1.8.7 or 1.9.2...
result = []
num_want = 4
i = 0
while (elem = my_array[i]) && my_array.length < num_want
result << elem if elem.some_condition
i += 1
end

You could make an Enumerable-like extension which has your desired selectn semantics:
module SelectN
def selectn(n)
out = []
each do |e|
break if n <= 0
if yield e
out << e
n -= 1
end
end
out
end
end
a = (0..9).to_a
a.select{ |e| e%3 == 0 } # [0, 3, 6, 9]
a.extend SelectN
a.selectn(1) { |e| e%3 == 0 } # [0]
a.selectn(3) { |e| e%3 == 0 } # [0, 3, 6]
# for convenience, you could inject this behavior into all Arrays
# the usual caveats about monkey-patching std library behavior applies
class Array; include SelectN; end
(0..9).to_a.selectn(2) { |e| e%3 == 0 } # [0,3]
(0..9).to_a.selectn(99) { |e| e%3 == 0 } # [0,3, 6, 9]

Why not flip this around and do the #take before the #select:
my_array.take(n).select { |elem| ... }
That will ensure you only do your computation for n number of items.
EDIT:
Enumerable::Lazy is known to be slower, but if your computation is known to be more computationally expensive than the lazy slowness, you can use the Ruby 2.0 feature:
my_array.lazy.select { |elem| ... }.take(n)
See: http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/

I guess broken loop can be done in old-fashioned loop style with break or something like this:
n = 5
[1,2,3,4,5,6,7].take_while { |e| n -= 1; n >= 0 && e < 7 }
In functional language this would be recursion, but without TCO it doesn't make much sense in Ruby.
UPDATE
take_while was stupid idea as dbenhur pointed out, so I don't know anything better than a loop.

Related

Permutational Primes Kata optimatization

I am solving the Permutational Primes Kata using Ruby. I manage to find out Brute-force solution but it exceeds the time limits. I need to optimize my code but I don't have any idea how to do this. The Kata.
require 'prime'
def permutational_primes(n_max, k_perms)
result_h = {}
result_keys = []
Prime.each(n_max) do |prime|
perms = prime.digits.permutation.to_a.map(&:join).map(&:to_i).uniq
prime_no_length = prime.to_s.length
perms = perms.delete_if { |el| el.to_s.length < prime_no_length }
# elimianate number greater than n_max
perms = perms.delete_if { |el| el > n_max }
next if (perms & result_keys).any?
perms = perms.delete_if { |el| !Prime.prime?(el) }
# minus one because we include
if perms.count - 1 == k_perms
result_h[prime] = perms
result_keys.append(prime)
end
end
return [0, 0, 0] if result_keys.empty?
[result_h.count, result_keys[0], result_keys[result_keys.count-1]]
end
Some low-hanging fruit:
Benchmarking is one way to understand what parts are more computationally expensive than others (likely Prime.prime?)
Find work that you're doing repeatedly or checks for information that you already know every Prime.each loop and cache it, trading memory for computation, e.g. Prime.prime?
All the common Enumerable methods create new Arrays. Instead, reuse existing arrays, e.g. map!
I have not yet thoroughly tested the following, but this general approach should speed things up considerably. There are two main elements that improved efficiency: use of the method Prime::each and maintaining a set of prime permutations already tested, to avoid unnecessary testing of duplicates.
require 'prime'
require 'set'
def permutational_primes(nMax, permutes)
skips = Set.new
enum = Prime.each
arr = []
while (prime = enum.next) < nMax
next if skips.include?(prime)
a = prime.digits.permutation.with_object([]) do |perm,a|
next if perm[-1].zero?
n = perm.reverse.join.to_i
if n < nMax && !skips.include?(n) && Prime.prime?(n)
skips << n
a << n
end
end
a.each { |n| skips << n }
next if a.size != permutes + 1
arr << a.min
end
[arr.size, arr.size.zero? ? 0 : arr.min, arr.size.zero? ? 0 : arr.max]
end
permutational_primes(1000, 3)
#=> [3, 149, 379]
This passes all tests but times out. I'm working on another optimization.
Explanation is under construction...

Combine and sort 2 arrays

This question was asked somewhere else, but I just wanted to check if what I did was applicable given the rspec circumstances:
Write a method that takes two sorted arrays and produces the sorted array that combines both.
Restrictions:
Do not call sort anywhere.
Do not in any way modify the two arrays given to you.
Do not circumvent (2) by cloning or duplicating the two arrays, only to modify the copies.
Hint: you will probably need indices into the two arrays.
combine_arrays([1, 3, 5], [2, 4, 6]) == [1, 2, 3, 4, 5, 6]
Can you just combine the two arrays into a single array and then run a typical bubble sort?
def combine_arrays(arr1,arr2)
final = arr1 + arr2
sorted = true
while sorted do
sorted = false
(0..final.length - 2).each do |x|
if final[x] > final[x+1]
final[x], final[x+1] = final[x+1], final[x]
sorted = true
end
end
end
final
end
p combine_arrays([1,3,5],[2,4,6]) => [1, 2, 3, 4, 5, 6]
Here is a variant which relies solely on Ruby's enumerators. The result is short and sweet.
# merge two sorted arrays into a sorted combined array
def merge(a1, a2)
[].tap do |combined|
e1, e2 = a1.each, a2.each
# The following three loops terminate appropriately because
# StopIteration acts as a break for Kernel#loop.
# First, keep appending smaller element until one of
# the enumerators run out of data
loop { combined << (e1.peek <= e2.peek ? e1 : e2).next }
# At this point, one of these enumerators is "empty" and will
# break immediately. The other appends all remaining data.
loop { combined << e1.next }
loop { combined << e2.next }
end
end
The first loop keeps grabbing the minimum of the two enumerator values until one of the enumerators runs out of values. The second loop then appends all remaining (which may be none) values from the first array's enumerator, the third loop does the same for the second array's enumerator, and tap hands back the resulting array.
Sure, you can do that but you are overlooking a real gimmee - the two arrays you are given will already be sorted.
def combine_arrays(A1, A2)
retVal = Array.CreateInstance(System::Int32, A1.Length + A2.Length - 1)
i = 0
j = 0
while i < A1.Length | j < A2.Length
if i < A1.Length and self.A1(i) < self.A2(j) then
self.retVal(i + j) = self.A1(i)
i += 1
else
self.retVal(i + j) = self.A2(j)
j += 1
end
end
return retVal
end
This is based on the same logic as Dale M's post, but in proper ruby:
def combine_arrays(arr1,arr2)
[].tap do |out|
i1 = i2 = 0
while i1 < arr1.size || i2 < arr2.size
v1 = arr1[i1]
v2 = arr2[i2]
if v1 && (!v2 || v1 < v2)
out << v1
i1 += 1
else
out << v2
i2 += 1
end
end
end
end
combine_arrays([1,3,5], [2,4,6])
Take a look at this one:
def merge(arr1, arr2)
arr2.each { |n| arr1 = insert_into_place(arr1, n) }
arr1.empty? ? arr2 : arr1
end
def insert_into_place(array, number)
return [] if array.empty?
group = array.group_by { |n| n >= number }
bigger = group[true]
smaller = group[false]
if bigger.nil?
number > smaller.last ? smaller << number : smaller.unshift(number)
else
(smaller << number) + bigger
end
end

Ruby - Return duplicates in an array using hashes, is this efficient?

I have solved the problem using normal loops and now using hashes, however I am not confident I used the hashes as well as I could have. Here is my code:
# 1-100 whats duplicated
def whats_duplicated?(array)
temp = Hash.new
output = Hash.new
# Write the input array numbers to a hash table and count them
array.each do |element|
if temp[element] >= 1
temp[element] += 1
else
temp[element] = 1
end
end
# Another hash, of only the numbers who appeared 2 or more times
temp.each do |hash, count|
if count > 1
output[hash] = count
end
end
# Return our sorted and formatted list as a string for screen
output.sort.inspect
end
### Main
# array_1 is an array 1-100 with duplicate numbers
array_1 = []
for i in 0..99
array_1[i] = i+1
end
# seed 10 random indexes which will likely be duplicates
for i in 0..9
array_1[rand(0..99)] = rand(1..100)
end
# print to screen the duplicated numbers & their count
puts whats_duplicated?(array_1)
My question is really what to improve? This is a learning excercise for myself, I am practising some of the typical brain-teasers you may get in an interview and while I can do this easily using loops, I want to learn an efficient use of hashes. I re-did the problem using hashes hoping for efficiency but looking at my code I think it isn't the best it could be. Thanks to anyone who takes an interest in this!
The easiest way to find duplicates in ruby, is to group the elements, and then count how many are in each group:
def whats_duplicated?(array)
array.group_by { |x| x }.select { |_, xs| xs.length > 1 }.keys
end
whats_duplicated?([1,2,3,3,4,5,3,2])
# => [2, 3]
def whats_duplicated?(array)
array.each_with_object(Hash.new(0)) { |val, hsh| hsh[val] += 1 }.select { |k,v| v > 1 }.keys
end
I would do it this way:
def duplicates(array)
counts = Hash.new { |h,k| h[k] = 0 }
array.each do |number|
counts[number] += 1
end
counts.select { |k,v| v > 1 }.keys
end
array = [1,2,3,4,4,5,6,6,7,8,8,9]
puts duplicates(array)
# => [4,6,8]
Some comments about your code: The block if temp[element] == 1 seems not correct. I think that will fail if a number occurs three or more times in the array. You should at least fix it to:
if temp[element] # check if element exists in hash
temp[element] += 1 # if it does increment
else
temp[element] = 1 # otherwise init hash at that position with `1`
end
Furthermore I recommend not to use the for x in foo syntax. Use foo.each do |x| instead. Hint: I like to ask in interviews about the difference between both versions.

Division and Loops for Beginners

Could someone help me figure this out how to do this in Ruby?
I have an array of integers. For each of those integers, I need to find a divisor that is two digits long (whole numbers as well). Right now, the code is looping to infinity. The answer I'm trying to get is:
int_a = 2, int_b = 11, and x = 22
Here is the code:
[22, 33].each do |x|
x.to_f
int_a = 1
int_b = x.quo(int_a)
until int_a > 15 || int_b%2==0 && sprintf("%g", int_b).to_s.length == 2
puts "#{x}"
puts "#{int_a}"
puts "#{int_b}"
end
int_a += 1
end
I can't understand your code, but by your definition:
For each of those integers, I need to find a divisor that is two digits long(whole numbers as well)
Give this a try:
numbers = [22,33]
numbers.map do |n|
raise "invalid number" if n < 10
div = 10.0
div += 1 while (n%div) != 0
div
end
#result: [11,22]
As #fotanus, I can't understand your code, but answering your question, I used this code a while ago for finding divisors:
require 'prime'
def divisors_for(n)
n.prime_division.map do |n,mp|
(0..mp).map { |i| n**i }
end.inject([1]) do |a, factor_group|
a.product(factor_group)
end.map do |factors|
factors.flatten.reduce(:*)
end - [n]
end
[22, 23].map do |n|
divisors_for(n).select { |d| d.to_s.size == 2 }
end

Iterate over an infinite sequence in Ruby

I am trying to solve Project Euler problem #12:
The sequence of triangle numbers is generated by adding the natural
numbers. So the 7th triangle number
would be 1 + 2 + 3 + 4 + 5 + 6 + 7 =
28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five
divisors.
What is the value of the first triangle number to have over five
hundred divisors?
Here's the solution that I came up with using Ruby:
triangle_number = 1
(2..9_999_999_999_999_999).each do |i|
triangle_number += i
num_divisors = 2 # 1 and the number divide the number always so we don't iterate over the entire sequence
(2..( i/2 + 1 )).each do |j|
num_divisors += 1 if i % j == 0
end
if num_divisors == 500 then
puts i
break
end
end
I shouldn't be using an arbitrary huge number like 9_999_999_999_999_999. It would be better if we had a Math.INFINITY sequence like some functional languages. How can I generate a lazy infinite sequence in Ruby?
Several answers are close but I don't actually see anyone using infinite ranges. Ruby supports them just fine.
Inf = Float::INFINITY # Ruby 1.9
Inf = 1.0/0 # Ruby before 1.9
(1..Inf).include?(2305843009213693951)
# => true
(1..Inf).step(7).take(3).inject(&:+)
# => 24.0
In your case
(2..Inf).find {|i| ((2..( i/2 + 1 )).select{|j| i % j == 0}.count+2)==42 }
=> 2880
Your brute force method is crude and can, potentially, take a very long time to finish.
In Ruby >= 1.9, you can create an Enumerator object that yields whatever sequence you like. Here's one that yields an infinite sequence of integers:
#!/usr/bin/ruby1.9
sequence = Enumerator.new do |yielder|
number = 0
loop do
number += 1
yielder.yield number
end
end
5.times do
puts sequence.next
end
# => 1
# => 2
# => 3
# => 4
# => 5
Or:
sequence.each do |i|
puts i
break if i >= 5
end
Or:
sequence.take(5).each { |i| puts i }
Programming Ruby 1.9 (aka "The Pickaxe Book"), 3rd. ed., p. 83, has an example of an Enumerator for triangular numbers. It should be easy to modify the Enumerator above to generate triangular numbers. I'd do it here, but that would reproduce the example verbatim, probably more than "fair use" allows.
Infinity is defined on Float (Ruby 1.9)
a = Float::INFINITY
puts a #=> Infinity
b = -a
puts a*b #=> -Infinity, just toying
1.upto(a) {|x| break if x >10; puts x}
Currrent versions of Ruby support generators heavily:
sequence = 1.step
In Ruby 2.6 this becomes much easier:
(1..).each {|n| ... }
Source: https://bugs.ruby-lang.org/issues/12912
This would be best as a simple loop.
triangle_number = 1
i = 1
while num_divisors < 500
i += 1
triangle_number += i
# ...
end
puts i
As Amadan mentioned you can use closures:
triangle = lambda { t = 0; n = 1; lambda{ t += n; n += 1; t } }[]
10.times { puts triangle[] }
Don't really think it is much slower than a loop. You can save state in class object too, but you will need more typing:
class Tri
def initialize
#t = 0
#n = 1
end
def next
#t += n
#n += 1
#t
end
end
t = Tri.new
10.times{ puts t.next }
Added:
For those who like longjmps:
require "generator"
tri =
Generator.new do |g|
t, n = 0, 1
loop do
t += n
n += 1
g.yield t
end
end
puts (0..19).map{ tri.next }.inspect
Building on Wayne's excellent answer and in the Ruby spirit of doing things with the least number of characters here is a slightly updated version:
sequence = Enumerator.new { |yielder| 1.step { |num| yielder.yield num } }
Obviously, doesn't solve the original Euler problem but is good for generating an infinite sequence of integers. Definitely works for Ruby > 2.0. Enjoy!
On Christmas Day 2018, Ruby introduced the endless range, providing a simple new approach to this problem.
This is implemented by ommitting the final character from the range, for example:
(1..)
(1...)
(10..)
(Time.now..)
Or to update using Jonas Elfström's solution:
(2..).find { |i| ((2..( i / 2 + 1 )).select { |j| i % j == 0 }.count + 2) == 42 }
Hope this proves useful to someone!
I believe that fibers (added in Ruby 1.9 I believe) may be close to what you want. See here for some information or just search for Ruby Fibers

Resources