Related
def custom_each(array)
index = 0
while index < array.length
yield array[index]
index += 1
end
end
ages = [12, 45, 67, 89]
p custom_each(ages) { |num| num * 2 }
Any ideas? im a total beginner?
im doing this course https://www.rubyguides.com/2018/10/ruby-map-method/
Your custom_each method works just fine. All you have to do is move p inside the block:
# built-in each
ages.each { |num| p num * 2 }
# your custom_each
custom_each(ages) { |num| p num * 2 }
Output:
24
90
134
178
Note that the original Array#each doesn't return an altered array either. It returns an enumerator or the original array:
[12, 45, 67, 89].each
#=> #<Enumerator: [12, 45, 67, 89]:each>
[12, 45, 67, 89].each { |num| num * 2 }
#=> [12, 45, 67, 89]
By default last executed expression in the function will returned. The result of the block execution yield array[index] haven't saved and returned from the function custom_each. That's why it returns nil always
Try the below:
def custom_each(array)
index = 0
result = []
while index < array.length
result << yield(array[index]) # Saves the result of block execution in an array
index += 1
end
result # Returns the result
end
ages = [12, 45, 67, 89]
p custom_each(ages) { |num| num * 2 }
Output:
[24, 90, 134, 178]
I want to return an array of sums of multiples of 3 and 5 from 0 to n. And I want to return "invalid" when the input is a string, a float or < 0
def is_multiple_of_3_or_5(n)
if n.class == Integer && n > 0
n % 3 == 0 || n % 5 == 0 ? true : false
else
puts "invalid"
end
end
def sum_of_3_and_5_multiples(n)
if n.class == Integer
i = 0
array_of_multiples_of_3_and_5 = Array.new
while i < n
array_of_multiples_of_3_and_5 << i if is_multiple_of_3_or_5(i) == true
i += 1
end
array_of_multiples_of_3_and_5.inject(0, :+)
end
end
sum_of_3_and_5_multiples(-1)
To get the sums of multiples of 3 and 5 I got this but when I try with -1 that return me 0 instead "invalid", with"string"` that return me an error.
You havent' put any code in your sum_of_3_and_5_multiples method to handle what happens if is_multiple_of_3_or_5 is invalid (or to put it another way, a string). You also don't need to puts 'invalid', as this returns a value of null. Just 'invalid' will do:
def is_multiple_of_3_or_5(n)
if n.class == Integer && n > 0
n % 3 == 0 || n % 5 == 0 ? true : false
else
"invalid"
end
end
def sum_of_3_and_5_multiples(n)
if n.class == Integer
i = 0
array_of_multiples_of_3_and_5 = Array.new
while i < n
return "invalid" if is_multiple_of_3_or_5(i).is_a?(String)
array_of_multiples_of_3_and_5 << i if is_multiple_of_3_or_5(i) == true
i += 1
end
array_of_multiples_of_3_and_5.inject(0, :+)
end
end
sum_of_3_and_5_multiples(-1)
=> "invalid"
One could do that as follows.
def sum_of_3_and_5_multiples(n)
case n
when Float, String, -Float::INFINITY...0
return 'invalid'
end
((0..n).step(3).to_a + (0..n).step(5).to_a).uniq
end
sum_of_3_and_5_multiples(11.5)
#=> "invalid"
sum_of_3_and_5_multiples("11")
#=> "invalid"
sum_of_3_and_5_multiples(-340)
#=> "invalid"
sum_of_3_and_5_multiples(15)
#=> [0, 3, 6, 9, 12, 15, 5, 10]
sum_of_3_and_5_multiples(87)
#=> [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,
# 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87,
# 5, 10, 20, 25, 35, 40, 50, 55, 65, 70, 80, 85]
Alternative verbose option, using a monkey patch to String class and a custom Class, stealing from Cary's answer (https://stackoverflow.com/a/59876202/5239030) but with a three dot Range for excluding the extreme value.
Patching the String class for using methods like this Numeric#integer? and Numeric#positive?. I'd suggest to use Kernel#raise in case of error.
module MyStringPatch
def integer?
false
end
def positive?
false
end
end
String.include MyStringPatch
Writing the custom class
class MyNumber
def initialize(n)
raise 'Invalid' unless n.integer? && n.positive?
#n = n
end
def sum_of_3_and_5_multiples
(((0...#n).step(3).to_a + (0...#n).step(5).to_a).uniq).sum
end
end
Finally using it
n = 32
my_number = MyNumber.new(n)
p my_number.sum_of_3_and_5_multiples
#=> 225
Or ...in initialize': Invalid (RuntimeError) in case of n = "32" or n = -32 or n = 32.0.
You can use something like:
return "invalid" unless n.is_a? Integer || n.positive?
Taking a look at: https://rubystyle.guide/ may help
I've found this ! that worked !
def is_multiple_of_3_or_5(n)
n % 3 == 0 || n % 5 == 0 || n == 0 ? true : false
end
def sum_of_3_and_5_multiples(n)
puts n.class
if n.class == Integer && n >= 0
i = 0
array_of_multiples_of_3_and_5 = Array.new
while i < n
array_of_multiples_of_3_and_5 << i if is_multiple_of_3_or_5(i) == true
i += 1
end
return array_of_multiples_of_3_and_5.inject(0, :+)
end
if n.class != Integer || n < 0
return "invalid"
end
end
thanks for your help that was helpful !
I'm solving the '100 doors' problem from Rosetta Code in Ruby. Briefly,
there are 100 doors, all closed, designated 1 to 100
100 passes are made, designated 1 to 100
on the ith pass, every ith door is "toggled": opened if it's closed, closed if it's open
determine the state of each door after 100 passes have been completed.
Therefore, on the first pass all doors are opened. On the second pass even numbered doors are closed. On the third pass doors i for which i%3 == 0 are toggled, and so on.
Here is my attempt at solving the problem.
visit_number = 0
door_array = []
door_array = 100.times.map {"closed"}
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
end
}
visit_number += 1
end
print door_array
But it keeps printing me an array of 100 nil when I run it: Look at all this nil !
What am I doing wrong?
That's what your if clauses return. Just add a return value explicitly.
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
end
door_status
}
visit_number += 1
end
OR:
1.upto(10) {|i| door_array[i*i-1] = 'open'}
The problem is the outer if block doesn't explicitly return anything (thus returns nil implicitly) when the condition does not meet.
A quick fix:
visit_number = 0
door_array = []
door_array = 100.times.map {"closed"}
until visit_number == 100 do
door_array = door_array.map.with_index { |door_status, door_index|
if (door_index + 1) % (visit_number + 1) == 0
if door_status == "closed"
door_status = "open"
elsif door_status == "open"
door_status = "closed"
end
else #<------------- Here
door_status #<------------- And here
end
}
visit_number += 1
end
print door_array
Consider these approaches:
door_array.map { |door|
case door
when "open"
"closed"
when "closed"
"open"
end
}
or
rule = { "open" => "closed", "closed" => "open" }
door_array.map { |door| rule[door] }
or
door_array.map { |door| door == 'open' ? 'closed' : 'open' }
Code
require 'prime'
def even_nbr_divisors?(n)
return false if n==1
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even?
end
closed, open = (1..100).partition { |n| even_nbr_divisors?(n) }
closed #=> [ 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22,
# 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40,
# 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57,
# 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
# 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
# 92, 93, 94, 95, 96, 97, 98, 99],
open #= [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Explanation
All doors are initially closed. Consider the 24th door. It is toggled during the following passes:
pass 1: opened
pass 2: closed
pass 3: opened
pass 4: closed
pass 6: opened
pass 8: closed
pass 12: opened
pass 24: closed
Notice that the door is toggled once for each of 24's divisors. Therefore, if we had a method divisors(n) that returned an array of n's divisors, we could determine the number of toggles as follows:
nbr_toggles = divisors(24).size
#=> [1,2,3,4,6,8,12,24].size
#=> 8
Since the door is toggled an even number of times, we conclude that it will be in its original state (closed) after all the dust has settled. Similarly, for n = 9,
divisors(9).size
#=> [1,3,9].size
#=> 3
We therefore conclude door #9 will be open at the end, since 3 is odd.
divisors can be defined as follows.
def divisors(n)
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.first.product(*arr[1..-1]).map { |a| a.reduce(:*) }
end
For example,
divisors 24
#=> [1, 3, 2, 6, 4, 12, 8, 24]
divisors 9
#=> [1, 3, 9]
divisors 1800
#=> [1, 5, 25, 3, 15, 75, 9, 45, 225, 2, 10, 50, 6, 30, 150, 18, 90, 450,
# 4, 20, 100, 12, 60, 300, 36, 180, 900, 8, 40, 200, 24, 120, 600, 72,
# 360, 1800]
Since we only care if there are an odd or even number of divisors, we can instead write
def even_nbr_divisors?(n)
return false if n==1
arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } }
arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even?
end
For n = 24, the steps are as follows:
n = 24
a = Prime.prime_division(n)
#=> [[2, 3], [3, 1]]
arr = a.map { |v,exp| (0..exp).map { |i| v**i } }
#=> [[1, 2, 4, 8], [1, 3]]
b = arr.shift
#=> [1, 2, 4, 8]
arr
#=> [[1, 3]]
c = b.product(*arr)
#=> [[1, 1], [1, 3], [2, 1], [2, 3], [4, 1], [4, 3], [8, 1], [8, 3]]
d = c.map { |a| a.reduce(:*) }
#=> [1, 3, 2, 6, 4, 12, 8, 24]
e = d.size
#=> 8
e.even?
#=> true
Lastly,
(1..100).partition { |n| even_nbr_divisors?(n) }
returns the result shown above.
I want to select the first 10 elements of an array that match a certain condition without having to loop through the whole array. I know that find gets me the first element. So for example, the code below gives me the first prime that is larger than 100:
require 'prime'
puts Prime.find {|p| p > 100 } #=> 101
Is there a way to get the first 10 primes that are bigger then 100?
In Ruby 2.0+ you can write:
require 'prime'
Prime.lazy.select{|p| p > 100 }.take(10).to_a #=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
You can do it more manually like
def check_for_primes(start_number, desired_size)
result = []
suspect = start_number
while result.size < desired_size do
result << suspect if suspect.prime?
suspect += 1
end
result
end
check_for_primes 100, 10
#=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
with a simple ruby iteration.
Which works with all ruby versions.
instead of the (indisputably non ruby like) while loop, we can add #cary-swoveland 's variation, which has quite some ruby goodness in it.
check_enum_text(start_number, desired_size)
(start_number..1.0/0).each_with_object([]) do |n,arr|
if n.prime?
arr << n;
return arr if arr.size == desired_size
end
end
end
***********UPDATE***********
and some benchmarks for performance
require 'benchmark'
a_gazillion = 10000000000
Benchmark.bm do |x|
x.report("lazy_select") { Prime.lazy.select{|p| p > (a_gazillion / 1000) }.take(10).to_a }
x.report("prime_each") { arr = []; Prime.each{|p| arr << p if p > a_gazillion / 1000; break if arr.count == 10 } }
x.report("while_loop") { check_for_primes a_gazillion, 10 }
x.report("enum_text") { check_enum_text a_gazillion, 10 }
end
user system total real
lazy_select 75.360000 0.240000 75.600000 (84.259781)
prime_each 6.100000 0.040000 6.140000 ( 6.730646)
while_loop 0.620000 0.000000 0.620000 ( 0.655504)
enum_text 0.610000 0.000000 0.610000 ( 0.770726)
from what we see the two latest solutions are the ones that perform the best. From some extra benchmarking (by tweaking the desired_size) I can not conclude to which one is better
def bench(start, length)
Benchmark.bm do |x|
x.report("enum_text") { check_enum_text start, length }
x.report("while_loop") { check_for_primes start, length}
end
end
bench a_gazillion, 100
user system total real
enum_text 6.350000 0.000000 6.350000 ( 6.974557)
while_loop 6.530000 0.000000 6.530000 ( 7.330884)
bench a_gazillion, 500
user system total real
enum_text 31.880000 0.110000 31.990000 ( 36.723209)
while_loop 32.850000 0.060000 32.910000 ( 38.569744)
Performance is similar (actually #cary-swoveland's solution performs slightly better), so I will have to go with that solution since it is more ruby like!!
arr = []
Prime.each{|p| arr << p if p > 100; break if arr.count == 10 }
puts arr
Some of the answers have the disadvantage that they enumerate primes below the threshold multiple times. Here is one way to avoid that:
require 'prime'
def check_for_primes(start_number, desired_size)
return [] if desired_size.zero?
enum = Prime.each
[enum.find { |n| n >= start_number }] + enum.first(desired_size-1)
end
check_for_primes(100, 10)
#=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
Alternatively, this could be written:
def check_for_primes(start_number, desired_size)
return [] if desired_size.zero?
enum = Prime.each
(0..1.0/0).each_with_object([]) do |_,arr|
n = enum.next
if n >= start_number
arr << n
return arr if arr.size == desired_size
end
end
end
A simple iterative way:
require 'prime'
initial = 100
list = []
10.times do |x|
initial = Prime.find {|p| p > initial}
list << initial
end
puts list
You can use Prime.each(n) to have an upper limit:
Prime.each(1000).drop_while { |p| p <= 100 }.take(10)
# => [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
Alternatively, you can count have many primes are below 100, then take that amount + 10:
Prime.take(Prime.take_while { |p| p <= 100 }.count + 10)[-10..-1]
# => [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Cumulative array sum in Ruby
I have an array of integers like this
[20, 25, 40, 60]
How can I turn it into an array with each element representing the cumulative value of the elements before it, including itself?
[20, 45, 85, 145]
I'm using Rails 3.2.0 & ruby 1.9.3
s = 0
[20, 25, 40, 60].map{|e| s += e}
[20, 25, 40, 60].reduce([]) do |arr, v|
arr << (arr.last || 0) + v
end
Or an ugly one liner.
[20, 25, 40, 60].reduce([0]){ |a, v| a << a[-1] + v }[1..-1]
array = [20, 25, 40, 60]
(array.size - 1).times { |i| array[i + 1] += array[i] }
puts array
# => [20, 45, 85, 145]
arr = [20, 25, 40, 60]
first = []
sum = 0
arr.each do |e|
sum += e
first << sum
end
puts first
arr.each_with_index.map{|x, i| x + (i==0 ? 0 : arr[0..i-1].inject(:+))}
=> [20, 45, 85, 145]
Matlab:
B = cumsum(A)
Ruby:
class Array
def ruby_cumsum!
(1..size-1).each {|i| self[i] += self[i-1] }
self
end
end