Can I use the .each Method to Solve this sum problem? - ruby

still new to Ruby. Noob question, please bear with me. And thank you ahead of time.
I love the .each method over something like the while loop. The while loop is confusing for me. I love the neatness of the .each method. Can I use the .each method to solve this question below? I'm pulling my hair out trying to figure out if I can use this style loop.
Thank you for your help!
def sum_nums(max)
puts sum_nums(4) # => 10, because 1 + 2 + 3 + 4 = 10
puts sum_nums(5) # => 15

Yes , you can use the .each method to solve this question. Pulling hairs out is not the way however. Try initializing a variable to 0 outside the each- block, and add all values in the block to that variable.

So to answer the OP (and borrowing shamelessly from all the other answers)
def sum_nums(n)
(1..n).sum
end
puts sum_nums(5)
# => 15

Here are a few options of how to sum all numbers from 1 to n in Ruby:
1.upto(4).reduce(:+) # => 10
1.upto(5).reduce(:+) # => 15
(1..4).reduce(:+) # => 10
(1..5).reduce(:+) # => 15
# could use `each`, but it is doing nothing here.
(1..4).each.reduce(:+) # => 10
(1..5).each.reduce(:+) # => 15
# same thing with `each`, but keeping track of the sum manually
sum = 0
(1..4).each do |i|
sum += i
end
# i => 10
Basically you get an Enumerable (iterator/collection abstraction) that spans over the things you would like enumerate. In our case we would like to go from 1 to 4. We can get an Enumerable for that either by calling Integer#upto method (like so: 1.upto(4), or by using Range (like so (1..4)). Then we can use any Enumerable methods on the collection/iterator.
Enumerable#each simply calls a block for every element (and when called without a block, essentially does nothing, just returns the same Enumerable), but Enumerable also has built-in functions for finding minimum, maximum, reducing (in our case we're doing the sum, so reduce fits), etc. For more detailed information see docs for Enumerable.

An example way that comes into my mind.
def sum_nums(max)
sum = 0
array = Array.new(max) { |i| (i + 1) }
array.each { |element| sum += element }
puts sum
end
sum_nums(4) # => 10
sum_nums(5) # => 15

Related

Optimize print output where i use check on zero. Ruby

Currently, I'm having print like this
print ((stamp_amount[0], 'first mark') unless stamp_amount[0].zero?), (', ' if !stamp_amount[0].zero? && !stamp_amount[1].zero?),
((stamp_amount[1], 'second mark') unless stamp_amount[1].zero?)
stamp_amount is an array with 2 integer values
Let's say in the current situation stamp_amount[0] = 10 and stamp_amount[1] = 3
Output preview:
10 first mark, 3 second mark
So if stamp_amount[0] = 0 the 10 first mark, part won't be show. Same if stamp_amount[1] = 0 the , 3 second mark part won't be shown
For me, it seems a little bit incorrect in terms of theory. Could you please suggest me the more correct or less painful print of this? :)
Cheers!
Your code is trying to join a sequence of up to two elements with a separator. The joining is a solved problem, see Array#join.
The problem can be then reduced to "how can I produce the correct sequence, given my stamp_amount input". Now this can be done in a thousand ways. Here's one:
def my_print(stamp_amount)
ary = [
!stamp_amount[0].zero? && stamp_amount[0],
!stamp_amount[1].zero? && stamp_amount[1],
].select{|elem| elem }
ary.join(', ')
end
my_print([10, 3]) # => "10, 3"
my_print([0, 3]) # => "3"
my_print([10, 0]) # => "10"
my_print([0, 0]) # => ""
Here's another
ary = []
ary << stamp_amount[0] unless stamp_amount[0].zero?
ary << stamp_amount[1] unless stamp_amount[1].zero?
ary.join(', ')
Here's yet another. This version can handle stamp_amount of any length.
ary = stamp_amount.reject(&:zero?)
ary.join(', ')
I'd go with the third, but the second one may be the easiest to understand for a beginner.
Use the select, as an alternative to reject (shown in part 3 of the answer by Sergio Tulentsev). It is just asa readable, and depending on the context and on the future changes to the code, you may prefer one versus the other.
puts stamp_amount.select{ |a| !a.zero? }.join(", ")
A few examples of inputs and outputs are:
stamp_amount output
--------------------------------------------------------------------------
10, 3 10, 3
10, 0 10
0, 3 3
0, 0 (prints an empty line, because the selected array is empty)
You're calculating zero? on index points more often than is needed, but the first thing I would look at refactoring here is the readability of the code. It might be nicer to calculate the message to print outside of the print method and explain what is happening with variable names.
# rubocop is going to complain about variable assignment like this
first_amount, second_amount = *stamp_amount
We can actually use the reason rubocop prefers the .zero? over == 0 or .empty? method to guide our development. zero? is in essence just empty? but it communicates the meaning of what you are attempting to do in a better manner. I would use this reasoning when assigning strings to variables that explain what they are doing.
some_name_that_explains_what_this_is_0 = "#{first_amount} piecu centu marka"
some_name_that_explains_what_this_is_1 = "#{second_amount} tris centu marka"
Your current code is confusing as you have the possibility of printing a string like "10 tris centu marka" which does not make lexical sense and probably not what you are after considering tis evaluates to 'second mark', which would pose an issue if the first value is zero. We also could reject zero integers before we start converting them to strings.
array = [1, 0].reject(&:zero?)
Now we can take the array and do something like:
string = []
array.each_with_index { |e, i| string << "#{e} #{Ordinalize.new(i).ordinalize} mark" }
message = string.join(', ')
print(message)
# ord class
class Ordinalize
def initialize(value)
#value = value
end
def ordinalize
mapping[#value]
end
def mapping
# acounting for zero index
['first', 'second']
end
end
where we are calculating the ordinalization and letting our new class handle the sentence structure for us.
Outputs:
[1, 0] => "1 first mark"
[0, 1] => "1 first mark"
[1, 2] => "1 first mark, 2 second mark"

Adding numbers in succession

I'm trying to learn Ruby and I came across a problem online where I need to create something similar to this :
add(1) # => 1
add(1).(2) # => 3
add(1).(2).(3) # => 6
and so on.
I've read around and the closest I can get to having this work is with the following code :
def add(n)
Proc.new { |s| s + n }
end
Which works to an extent.
I can run the following :
add(1) # => #<Proc:0x007fb8aac309f0#(pry):2>
# or
add(1).(2) # => 3
But the moment I try doing this :
add(1).(2).(3)
I get the following error :
NoMethodError: undefined method call for 3:Integer
Why am I getting this error and how would I change this method so that it will accept as many new values as I give it to add itself without giving me an error?
For reference, this problem comes from CodeWars "A Chain Adding Function".
The easiest way to achieve this is to define Integer#call:
class Integer
def call(n)
self + n
end
end
def add(n)
n
end
puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6
The returned objects are plain Ruby Integers, not Proxy objects.
Note that it's probably not a good idea to modify such an important class. It's possible to use refinements in order to avoid breaking other Ruby parts:
module ChainAdding
refine Integer do
def call(n)
self + n
end
end
end
def add(n)
n
end
using ChainAdding
puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6
If you're learning Ruby, this kind of metaprogramming trick isn't what you should concentrate on first. It's cool to know that we can do this, it doesn't mean that we should, though.
You can't quite do what you are trying to do. The reason is that you have to return something and that something can't change based on whether you are going to continue the chain or not.
Note that some Rails objects give you the illusion that you can in the REPL (irb, pry), but they actually just redefine #inspect, which is called upon visualisation by said REPL.
Instead you can do something very similar, which has an even better interface IMO:
def add(starting_number)
sum = starting_number
accumulator = proc do |next_number|
if next_number
sum += next_number
accumulator
else
sum
end
end
end
add(1) # => #<Proc:0x007fb8ae20e860#(pry):4>
add(1).(2) # => #<Proc:0x007fb8ae4894f0#(pry):4>
add(1).() # => 1
add(1).(2).() # => 3
add(1).(2).(3).(4).() # => 10

ruby how could i make this factorization recursive till i end with a binary number?

i have this code, basically first i factorize for example the number 28 to:
[2,2,7]
and then i make a list of prime numbers and find the index of each factor in that list, so 2 is prime number with index 0 and 7 prime number with index 2 so it ends up like this:
[[0],[0],[2]]
with which another recursion would be:
[[0],[0],[[0]]]
which tranlated to binary would be:
1101101110111
but im stuck on this:
require 'prime'
def f(n)
Prime.prime_division(n).flat_map { |factor, power| [factor] * power }
end
n=rand(10000)
puts n
f=f (n)
require 'prime'
#list=Prime.take(10000)
g=[]
j=0
f.each do |j|
if j>10
i=f(#list.index(j))
g.push i
i=[]
else
g.push j
end
end
print g
You want to learn, so I won't do all the work for you.
Step 1
Please write those 3 methods :
def get_factors(integer)
# return an Array of Integers:
# get_factors(28) -> [2,2,7]
end
def get_factor_index(prime)
# return the index of prime in Prime.all :
# 2 -> 0
# 7 -> 2
end
def array_to_binary(nested_array)
# convert nested_array (with 0s in leaves) to binary
# [[0],[0],[[0]]] -> "1101101110111"
# Hint : Use Array#to_s, and then String#gsub 3 times to convert ',' to '', and '[' or ']' to 1
end
and come back once you're done. We'll work on the recursion.
Step 2
I modified a bit your answer just a bit. To make it clearer, I tried to use different names for variables and methods. Also, the last line of a method is returned automatically by Ruby. You don't need to define an extra variable. Methods could probably be written more efficiently but I didn't want you to not recognize your code.
Your get_factor_index does more than what I asked for BTW. I'm not sure we can use it like this :
require "prime"
def get_factors(integer)
Prime.prime_division(integer)
end
def nested_array(factors)
factors.flat_map { |factor, power| [factor] * power }
end
def get_factor_index(nested_array)
list=Prime.take(10000)
temp=[]
nested_array.each do |i|
p = list.index(i)
temp.push(p)
end
temp
end
def array_to_binary(array)
temp=array.to_s
temp=temp.gsub("[","1")
temp=temp.gsub("]","1")
temp=temp.gsub(",","")
temp.gsub(" ","")
end
Now, please write a method that uses all the above ones, converting 512 to "10000000001". I'm not sure it's the correct answer, but we'll work on that later.
Also, try this method on 20 (not 28!) and see what you get. Using the above methods, you could try to manually tailor a way to get [[0],[0],[2]]. It's not a problem if it just works for 20 at first.
If you're feeling adventurous, try to get [[0],[0],[[0]]] with the above methods.

How do I destructure a range in Ruby?

Is it possible to use destructuring in ruby to extract the end and beginning from a range?
module PriceHelper
def price_range_human( range )
"$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
end
end
I know that I can use array coercion as a really bad hack:
first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)
But is there a syntactical way to get begin and end without actually manually creating an array?
min, max = (1..10)
Would have been awesome.
You can use minmax to destructure ranges:
min, max = (1..10).minmax
min # => 1
max # => 10
If you are using Ruby before 2.7, avoid using this on large ranges.
The beginning and end? I'd use:
foo = 1..2
foo.min # => 1
foo.max # => 2
Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.
end is not the same as max: in 1...10, end is 10, but max is 9
That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):
start_value = 1
end_value = 2
foo = start_value...end_value
foo.end # => 2
foo.max # => 1
foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1
max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.
In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.
... is more confusing and leads to increased maintenance problems so its use is not recommended.
No, Until I am proven incorrect by Cary Swoveland, Weekly World News or another tabloid, I'll continue believing without any evidence that the answer is "no"; but it's easy enough to make.
module RangeWithBounds
refine Range do
def bounds
[self.begin, self.end]
end
end
end
module Test
using RangeWithBounds
r = (1..10)
b, e = *r.bounds
puts "#{b}..#{e}"
end
Then again, I'd just write "#{r.begin.number_to_currency}..#{r.end.number_to_currency}" in the first place.
Amadan's answer is fine. you just need to remove the splat (*) when using it since it is not needed
eg,
> "%s to %s" % (1..3).bounds.map{|x| number_to_currency(x)}
=> "$1.00 to $3.00"

Ruby find in array with offset

I'm looking for a way to do the following in Ruby in a cleaner way:
class Array
def find_index_with_offset(offset, &block)
[offset..-1].find &block
end
end
offset = array.find_index {|element| element.meets_some_criterion?}
the_object_I_want =
array.find_index_with_offset(offset+1) {|element| element.meets_another_criterion?}
So I'm searching a Ruby array for the index of some object and then I do a follow-up search to find the first object that matches some other criterion and has a higher index in the array. Is there a better way to do this?
What do I mean by cleaner: something that doesn't involve explicitly slicing the array. When you do this a couple of times, calculating the slicing indices gets messy fast. I'd like to keep operating on the original array. It's easier to understand and less error-prone.
NB. In my actual code I haven't monkey-patched Array, but I want to draw attention to the fact that I expect I'm duplicating existing functionality of Array/Enumerable
Edits
Fixed location of offset + 1 as per Mladen Jablanović's comment; rewrite error
Added explanation of 'cleaner' as per Mladen Jablanović's comment
Cleaner is here obviously subjective matter. If you aim for short, I don't think you could do better than that. If you want to be able to chain multiple such finds, or you are bothered by slicing, you can do something like this:
module Enumerable
def find_multi *procs
return nil if procs.empty?
find do |e|
if procs.first.call(e)
procs.shift
next true if procs.empty?
end
false
end
end
end
a = (1..10).to_a
p a.find_multi(lambda{|e| e % 5 == 0}, lambda{|e| e % 3 == 0}, lambda{|e| e % 4 == 0})
#=> 8
Edit: And if you're not concerned with the performance you could do something like:
array.drop_while{|element|
!element.meets_some_criterion?
}.drop(1).find{|element|
element.meets_another_criterion?
}

Resources