Count iterations performed on enumerable object - ruby

I need to select from an array the elements that satisfy some condition, and count the number of iterations it took. For example:
array = [1,2,3,4,5...1,000,000]
count = 0
array.keep_if { |x| x % 2 == 0 }
I want to increase the counter every time the condition x % 2 == 0 is satisfied. Is there a way to tell how many iterations took place?

I think this should work as expected.
array.keep_if { |x|
keep = (x % 2 == 0 ? true : false)
count = count + 1 if keep
keep
}

Just out of curiosity, whether you won’t call Array#size on result:
array.reduce([0, []]) { |memo, el|
next memo unless el % 2 == 0
memo[0] += 1
memo.last << el
memo
}
#β‡’ [
# [0] 500,
# [1] [ ... ] # the filtered result
#]

I would chose a simpler solution. The count you seek will be equivalent with the length of the resulting array. So you can use a classic select method and then count the results.
array = (1..1000000).to_a
[res = array.select {|x| x % 2 == 0}, count = res.length]
puts the reduced array to res, and the number of true conditions on count

Related

Strange behavior with bsearch_index

tmp = [-3,3,5]
p "test: #{tmp.bsearch_index{|j| j == -3}}"
In the above code, I get response as nil. If I compare j against 3, or 5, it works. Why does bsearch_index does not consider very first element?
You need to write
tmp.bsearch_index{|n| n >= -3} #=> 0
This uses Array#bsearch_index's find minimum mode, which returns the smallest value in the array that satisfies the expression in the block. For example,
tmp.bsearch { |n| n >= 0 } #=> 3
tmp.bsearch_index { |n| n >= 0 } #=> 1
In this mode, to quote the doc for Array#bsearch, "the block must always return true or false, and there must be an index i (0 <= i <= ary.size) so that the block returns false for any element whose index is less than i, and the block returns true for any element whose index is greater than or equal to i. This method returns the i-th element. If i is equal to ary.size, it returns nil."
If the block were { |n| n == -3 } there would be no index i, 0 <= i <= tmp.size #=> 3 that has the property that tmp[j] == -3 is false for all j < i and true for all j >= 1.
If the block calculation were tmp[j] == 5 the requirement would be satisfied (for index 2) so the correct value would be returned. If the block calculation were tmp[j] == 3 the requirement would not be satisfied (tmp[2] == 3 #=> false); the fact that the correct index is returned is only due to the way the method has been implemented. If
tmp = [-3, 3, 5, 6]
then nil is returned for n == 3 as well as for n == -3:
tmp.bsearch_index { |n| n == 3 } #=> nil
bsearch has a second mode, find any mode. (See the doc for Array#bsearch for details.) In this case we might write one of the following:
tmp.bsearch_index { |n| -3 - n } #=> 0
tmp.bsearch_index { |n| 3 - n } #=> 1
tmp.bsearch_index { |n| 5 - n } #=> 2
tmp.bsearch_index { |n| 4 - n } #=> nil
This mode would be useful here if nil were to be returned when no element in the array evaluates to zero in the block. In other contexts it has a multitude of uses.

Big O Complexity of Algorithm

This method seeks to express num as a product of elements in arr.
For e.g method1(37,[1,3,5]) returns [2,0,7]
// arr is an array of divisors sorted in asc order, e.g. [1,3,5]
def method1(num, arr)
newArr = Array.new(arr.size, 0)
count = arr.size - 1
while num > 0
div = arr[count]
if div <= num
arr[count] = num/div
num = num % div
end
count = count - 1
end
return newArr
end
Would really appreciate if you could give me some help to derive the complexity of the algorithm. Please also feel free to improve the efficiency of my algorithm
Here's a refactored version of your code :
def find_linear_combination(num, divisors)
results = divisors.map do |divisor|
q, num = num.divmod(divisor)
q
end
results if num == 0
end
puts find_linear_combination(37, [5, 3, 1]) == [7, 0, 2]
puts find_linear_combination(37, [1, 3, 5]) == [37, 0, 0]
puts find_linear_combination(37, [5]).nil?
With n being the size of divisors, this algorithm clearly appears to be O(n). There's only one loop (map) and there's only one integer division inside the loop.
Note that the divisors should be written in descending order. If no linear combination is found, the method returns nil.
If you want to sort divisors, the algorithm would be O(n*log n). It could also be a good idea to append 1 if necessary (O(1)).
Here's what you can do:
def method1(num, arr)
newArr = Array.new(arr.size, 0)
count = arr.size()-1
while num>0
div = arr[count]
if div <= num
arr[count] = num / div
num = num % div
end
count = count + 1
end
return arr
end
ar = Array.new(25000000) { rand(1...10000) }
t1 = Time.now
method1(37, ar)
t2 = Time.now
tdelta = t2 - t1
print tdelta.to_f
Output:
0.102611062
Now double the array size:
ar = Array.new(50000000) { rand(1...10) }
Output:
0.325793964
And double again:
ar = Array.new(100000000) { rand(1...10) }
Output:
0.973402568
So an n doubles, the duration roughly triples. Since O(3n) == O(n), the
whole algorithm runs in O(n) time, where n represents the size of the input
array.

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"

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

I ran into issue here with splitting array and adding it up

i am trying to find if array has 2 digits number and if i find one i want to add the two digit and make it single. then add all the numbers in array to come up with a a sum. here is my code so far. and also i am a noob and learning
class Imei
attr_accessor :Imei, :split_total1, :split_total2
def initialize(imei)
#imei = imei.to_i
#split_total1 = []
#split_total2 = []
end
def check_two_digit(num)
if num.to_s.length == 2
num = num.to_s.split(//).partition.with_index{|_,i| i.odd?}
num.each do |a, b|
a.to_i + b.to_i
end
else
num.to_i
end
end
def check_imei
if #imei.to_s.length == 15
split1, split2 = #imei.to_s.split(//).partition.with_index{|_, i| i.odd?}
split1.each do |a|
#split_total1 << check_two_digit(a.to_i * 2)
end
split2.pop
split2.each do |a|
#split_total2 << a.to_i
end
else
puts "IMEI NUMBER INVALID"
end
end
end
imei = Imei.new(123456789102222)
imei.check_imei
puts imei.split_total1.inspect
puts imei.split_total2.inspect
Find below the Luhn Algorithm I wrote in ruby
def luhn_10_valid? imei
digits = imei.reverse.chars.map(&:to_i)
digits.each_with_index.inject(0) do |sum, (digit, i)|
digit *= 2 if i.odd?
digit -= 9 if digit > 9
sum += digit
end % 10 == 0
end
For Luhn algorithm I really like the divmod method, which simplifies things
array.reverse.each_slice(2).map { |x, y|
y ||= 0
[x, (y * 2).divmod(10)]
}.flatten.inject(:+) % 10 == 0
If a contains only non-negative integers, this is one Ruby-like way to compute the sum:
a.reduce(0) {|t,i| t + (((10..99).cover? i) ? i.divmod(10).reduce(:+) : i )}
Explanation:
If i => 46, (10..99).cover?(46) => true, 46.divmod(10) => [4,6], [4,6].reduce(:+) => 10. Recall that reduce is aka inject. [4,6]reduce(:+) has the same result as (but,technically, is not 'equivalent to'):
[4,6].reduce { |u,j| u+j }
The zero initial value is needed for the first reduce, as
a[46].reduce {|t,i| t+(((10..99).cover? i) ? i.divmod(10).reduce(:+):i)}
#=> 46
which is incorrect.
If a instead contains string representations of integers and/or the integers may be negative, let me know and I'll change my answer accordingly.

Resources