Is each slower than while in Ruby? - ruby

The following two functions, which check if a number is prime:
def prime1?(prime_candidate)
return true if [1, 2].include? prime_candidate
range = 2.upto(Math.sqrt(prime_candidate).ceil).to_a
i = 0
while i < range.count
return false if prime_candidate % range[i] == 0
range = range.reject { |j| j % range[i] == 0 }
end
true
end
def prime2?(prime_candidate)
return true if [1, 2].include? prime_candidate
range = 2.upto(Math.sqrt(prime_candidate).ceil).to_a
range.each do |i|
return false if prime_candidate % i == 0
range = range.reject { |j| j % i == 0 }
end
true
end
yield the following benchamrking result when testing with a very large prime (5915587277):
user system total real
prime1: 2.500000 0.010000 2.510000 ( 2.499585)
prime2: 20.700000 0.030000 20.730000 ( 20.717267)
Why is that? Is it because in the second function range does not get modified by the reject, so the each is iterating over the original long range?

When you do range=range.reject {..}, you don't modify the parent range (which you shouldn't do, because it would mess up the iteration--you need reject! to do that) but rather construct a temporary array which only gets assigned to the parent range variable at the end of the iteration.
The each iteration in prime2 runs over the whole original range, not the shortened which, before the loop ends, only exist in the block.
The while version modifies the original array and is therefore quicker (BTW, you realize that i remains zero and it's the range.count that changes (decreases) in that while condition and that reject iterates over the WHOLE array again--even the beginning where there couldn't possibly be any more nonprimes to reject).
You'll get a much faster result if you improve the logic of your code. That array manipulation is costly and for this, you don't even need an array:
def prime3?(prime_candidate)
return false if prime_candidate==1
return true if prime_candidate==2
range = 2..(Math.sqrt(prime_candidate).ceil)
range.all? {|x| prime_candidate % x !=0 }
end #about 300× times as fast for your example as prime1? on my PC

Related

How to compare 1 number to an entire array?

Create a function that takes an array of hurdle heights and a jumper's jump height, and determine whether or not the hurdler can clear all the hurdles. A hurdler can clear a hurdle if their jump height is greater than or equal to the hurdle height.
My code:
def hj (arr, h)
i = 0
while i < arr.length
j = 0
while j < arr.length
if arr[i] > h
return false
end
j += 1
end
return true
i += 1
end
end
puts hj([2, 3, 6, 1, 3, 1, 8], 7)
Desired output: true if h is >= to any number in the array; false if h is < any number in the array (I want true or false to display once)
Where I'm questioning my own code:
Not sure if I need two while statements
the current array being passed should output false
loop seems to only be comparing the first set of numbers, so 7 and 2. Not sure why the loop is stopping.
Not sure if I'm utilizing true and false correctly
Feel like I should be using a block for this, but not sure where to implement it.
Thank you in advance for any feedback.
Some solutions:
Using loop
def hj(arr, h)
for elem in arr
return false if elem > h
end
true
end
See? Only one loop. Actually this is the most unruby implementation.
Using Enumerable#all?
def hj(arr, h)
arr.all?{|elem| elem <= h}
end
This is the most intuitive and most Ruby implementation.
Using Enumerable#max
If one can jump over the highest hurdle, he can jump over all hurdles.
def hj(arr, h)
arr.max <= h
end
Not sure if I need two while statements
You don't. You only need to traverse the list once. You're traversing, not sorting / reordering.
loop seems to only be comparing the first set of numbers, so 7 and 2. Not sure why the loop is stopping.
This is because you are using return true as the second last statement of your outer loop. Return interrupts function execution and returns immediately to the calling function - in this case, the last line of your program.
Feel like I should be using a block for this, but not sure where to implement it.
A block is the idiomatic ruby way to solve this. You are, essentially, wanting to check that your second parameter is larger than any value in the list which is your first parameter.
A solution in idiomatic ruby would be
def hj (arr, h)
# return true if h >= all elements in arr, false otherwise
# given arr = [1, 2, 3] and h = 2,
# returns [ true, true, false ] which all? then returns as false
# (since all? returns the boolean AND of the results of the block evaluation
arr.all? { |elem| elem <= h }
end

Speeding up solution to algorithm

Working on the following algorithm:
Given an array of non-negative integers, you are initially positioned
at the first index of the array.
Each element in the array represents your maximum jump length at that
position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.
Below is my solution. It tries every single potential step, and then memoizes accordingly. So if the first element is three, the code takes three steps, two steps, and one step, and launches three separate functions from there. I then memoized with a hash. My issue is that the code works perfectly fine, but it's timing out for very large inputs. Memoizing helped, but only a little bit. Am I memoizing correctly or is backtracking the wrong approach here?
def can_jump(nums)
#memo = {}
avail?(nums, 0)
end
def avail?(nums, index)
return true if nums.nil? || nums.empty? || nums.length == 1 || index >= nums.length - 1
current = nums[index]
true_count = 0
until current == 0 #try every jump from the val to 1
#memo[index + current] ||= avail?(nums, index + current)
true_count +=1 if #memo[index + current] == true
current -= 1
end
true_count > 0
end
Here's a 𝑂(𝑛) algorithm:
Initialize 𝑚𝑎𝑥 to 0.
For each number 𝑛𝑖 in 𝑁:
If 𝑖 is greater than 𝑚𝑎𝑥, neither 𝑛𝑖 nor any subsequent number can be reached, so
return false.
If 𝑛𝑖+𝑖 is greater than 𝑚𝑎𝑥, set 𝑚𝑎𝑥 to 𝑛𝑖+𝑖.
If 𝑚𝑎𝑥 is greater than or equal to the last index in 𝑁
return true.
Otherwise return false.
Here's a Ruby implementation:
def can_jump(nums)
max_reach = 0
nums.each_with_index do |num, idx|
return false if idx > max_reach
max_reach = [idx+num, max_reach].max
end
max_reach >= nums.size - 1
end
p can_jump([2,3,1,1,4]) # => true
p can_jump([3,2,1,0,4]) # => false
See it on repl.it: https://repl.it/FvlV/1
Your code is O(n^2), but you can produce the result in O(n) time and O(1) space. The idea is to work backwards through the array keeping the minimum index found so far from which you can reach index n-1.
Something like this:
def can_jump(nums)
min_index = nums.length - 1
for i in (nums.length - 2).downto(0)
if nums[i] + i >= min_index
min_index = i
end
end
min_index == 0
end
print can_jump([2, 3, 1, 1, 4]), "\n"
print can_jump([3, 2, 1, 0, 4]), "\n"

Given an array of integers and target, return true if any two elements sum to target

As the title states, I'm looking to find two elements whose sum is equal to the target integer. I've already worked out the solution below, but this works only for unique integers. I'm having an issue when it comes to duplicate values. Of course, I can use multiple loops that keep track of two separate indices and, in this way, make sure those two indices are the same. However, I wanted to see if there was a way to solve this with one iteration.
two_sum([1,2,3,4,5,6], 8) = true
two_sum([4,4], 8) = false
def two_sum(array, target)
idx = 0
while idx < array.length
complement = target - array[idx]
if array.include?(complement) && complement != array[idx]
return true
end
idx+=1
end
return false
end
require 'set'
def two_sum(arr, tot)
st = Set.new
arr.each { |n| st.include?(tot-n) ? (return true) : st << n }
false
end
two_sum [1,2,3,4,5,6], 8 #=> true
two_sum [4,4], 8 #=> true
two_sum [1,2,3,4,5,6], 3421 #=> false
If you'd prefer to return the two values that sum to tot (when true), replace true with [n, tot-n] (or just return n, the other being tot - n).
I used a set rather than an array for faster lookups.
def two_sum(array, target)
array.combination(2).each { |pair| return true if pair.inject(:+) == target }
return false;
end

Nested each statements aren't working

I'm trying to write a program in Ruby that finds the prime factors of a given number, without using Ruby's .Prime class. The code I wrote seems logical (if roundabout) to me, but for some reason the last line of code doesn't seem to work and I have no idea why. The code still just returns all of the factors of a given number, not the prime ones.
def prime(n)
array = []
r = Range.new(2, n - 1)
r.each { |x| array << x if n % x == 0 }
array.each { |x| puts x if (2..x - 1).each { |p| x % p != 0 }}
end
You want to check .all? numbers in (2..x - 1), not .each:
def prime(n)
array = []
r = Range.new(2, n - 1)
r.each { |x| array << x if n % x == 0 }
array.each { |x| puts x if (2..x - 1).all? { |p| x % p != 0 }}
end
By the way, I would also recommend to give meaningful names to your variables, because now it's really hard to read your code, this is much clearer implementation:
def prime?(num)
return false if num < 2
(2..Math.sqrt(num).to_i).each do |i|
return false if num % i == 0
end
true
end
def prime_factors(num)
(2..num - 1).inject([]) do |factors, i|
(num % i == 0) ? factors << i : factors
end.select { |factor| prime?(factor) }
end
p prime_factors(44)
def prime_factors(n)
# It's clear what factors will hold.
# It helps you when you or someone else read it out
# after a while.
factors = []
# Keep the r. No problem.
r = Range.new(2, n-1)
# Array#select is nice for this task.
# select is good in case where you need to filter out certain
# values out of a list. It nicely separates the selection task.
factors = r.select { |x| n % x == 0 }
# It's better not to go for double block on a single line.
# It will become more readable this way.
# Also it's better to handle how the result is displayed outside
# the function and just to return the computed values.
factors.select do |x|
(2..x - 1).all? { |p| x % p != 0 }
end
end
It seems more logical to split this single function into three factors n, prime n, and prime_factors n then compose them together. This design is more modular and more suitable to testing the individual parts. e.g. If all of the logic is globbed together, how can you say for certain that your program find primes correctly?
def factors n
(2..(n/2).floor).select {|x| n % x == 0 }
end
def prime? n
return false unless n >= 2
(2..Math.sqrt(n).floor).all? {|x| n % x != 0 }
end
def prime_factors n
factors(n).select {|x| prime? x }
end

Need help understanding what "(2..Math.sqrt(n)).none?" means in a method that sums the primes below a number

def prime_sum_below(x)
primes = (2..x).select { |n| (2..Math.sqrt(n)).none? { |i| (n % i).zero? }}
sum = primes.inject { |sum, i| sum + i }
end
The method sums the primes below x. I have trouble understanding "(2..Math.sqrt(n)).none?". What exactly does it do?
From the ruby guide, .none? passes each element of the collection to the given block. The method returns true if the block never returns true for all elements. If the block is not given, none? will return true only if none of the collection members is true.
I don't fully understand that, could someone please clarify?
Let me rephrase it like this:
primes = (2..x).select do |n|
(2..Math.sqrt(n)).none? do |i|
(n % i).zero?
end
end
And then go through each line:
# It selects a number if the following block returns true
primes = (2..x).select do |n|
# It takes all of the elements from 2 to the square root of n
(2..Math.sqrt(n))
# Then passes that into another block, returning true if none of the elements return true
.none? do |i|
# If it never divides evenly, then it returns true
(n % i).zero?
end
end
So if (n % i).zero? returns true, it means that something goes into n, meaning n cannot be a prime number

Resources