How can this be achieved in Ruby? Can it be done without repeating the variable?
Javascript:
b = a || 7
This assigns a if a is not 0 and 7 otherwise
One specific case is converting date.wday to 7 if it returns 0 (Sunday).
Just out of curiosity:
class Object
def javascript_or?(other)
(is_a?(FalseClass) || nil? || '' == self || 0 == self) ? nil : self
end
end
and:
a = b.javascript_or?(7)
There are only two falsy values in Ruby: nil and false. So, if you really want this approach
a = b == 0 ? 7 : b
is a plausible solution, because 0 can't be evaluated as false.
However, a better option for your need is cwday, and not wday. Then you don't need to make this comparison anymore, because it returns 1 for Monday, 2 for Tuesday, and finally 7 for Sunday, as you need.
date = Date.new(2016,19,6) # => Jun 19 2016, Sunday
date.cwday # => 7
For the particular case of 0 and 7:
a = (b + 6) % 7 + 1
:)
You can use ternary operator:
date.wday == 0 ? 7 : date.wday
What you're describing here is less of a logical problem and more of a mapping one:
WEEKDAY_MAP = Hash.new { |h,k| h[k] = k < 7 ? k : nil }.merge(0 => 7)
This one re-writes 1..6 to be the same, but 0 becomes 7. All other values are nil.
Then you can use this to re-write your day indicies:
b = WEEKDAY_MAP[a]
If at some point you want to tinker with the logic some more, that's also possible.
Related
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
def multiples_of(number)
number = number.to_f - 1.0
result = 0
if (number / 5.0) == 1 || (number / 3.0) == 1
return result = result + 5.0 + 3.0
elsif (number % 3).zero? || (number % 5).zero?
result += number
multiples_of(number-1)
else
multiples_of(number-1)
end
return result
end
p multiples_of(10.0)
My code is returning 9.0 rather than 23.0.
Using Core Methods to Select & Sum from a Range
It's not entirely clear what you really want to do here. This is clearly a homework assignment, so it's probably intended to get you to think in a certain way about whatever the lesson is. If that's the case, refer to your lesson plan or ask your instructor.
That said, if you restrict the set of possible input values to integers and use iteration rather than recursion, you can trivially solve for this using Array#select on an exclusive Range, and then calling Array#sum on the intermediate result. For example:
(1...10).select { |i| i.modulo(3).zero? || i.modulo(5).zero? }.sum
#=> 23
(1...1_000).select { |i| i.modulo(3).zero? || i.modulo(5).zero? }.sum
#=> 233168
Leave off the #sum if you want to see all the selected values. In addition, you can create your own custom validator by comparing your logic to an expected result. For example:
def valid_result? range_end, checksum
(1 ... range_end).select do |i|
i.modulo(3).zero? || i.modulo(5).zero?
end.sum.eql? checksum
end
valid_result? 10, 9
#=> false
valid_result? 10, 23
#=> true
valid_result? 1_000, 233_168
#=> true
There are a number of issues with your code. Most importantly, you're making recursive calls but you aren't combining their results in any way.
Let's step through what happens with an input of 10.
You assign number = number.to_f - 1.0 which will equal 9.
Then you reach the elsif (number % 3).zero? || (number % 5).zero? condition which is true, so you call result += number and multiples_of(number-1).
However, you're discarding the return value of the recursive call and call return result no matter what. So, your recursion doesn't have any impact on the return value. And for any input besides 3 or 5 you will always return input-1 as the return value. That's why you're getting 9.
Here's an implementation which works, for comparison:
def multiples_of(number)
number -= 1
return 0 if number.zero?
if number % 5 == 0 || number % 3 == 0
number + multiples_of(number)
else
multiples_of(number)
end
end
puts multiples_of(10)
# => 23
Note that I'm calling multiples_of(number) instead of multiples_of(number - 1) because you're already decrementing the input on the function's first line. You don't need to decrement twice - that would cause you to only process every other number e.g. 9,7,5,3
explanation
to step throgh the recursion a bit to help you understand it. Let's say we have an input of 4.
We first decrement the input so number=3. Then we hits the if number % 5 == 0 || number % 3 == 0 condition so we return number + multiples_of(number).
What does multiples_of(number) return? Now we have to evaluate the next recursive call. We decrement the number so now we have number=2. We hit the else block so now we'll return multiples_of(number).
We do the same thing with the next recursive call, with number=1. This multiples_of(1). We decrement the input so now we have number=0. This matches our base case so finally we're done with recursive calls and can work up the stack to figure out what our actual return value is.
For an input of 6 it would look like so:
multiples_of(6)
\
5 + multiples_of(5)
\
multiples_of(4)
\
3 + multiples_of(3)
\
multiples_of(2)
\
multiples_of(1)
\
multiples_of(0)
\
0
The desired result can be obtained from a closed-form expression. That is, no iteration is required.
Suppose we are given a positive integer n and wish to compute the sum of all positive numbers that are multiples of 3 that do not exceed n.
1*3 + 2*3 +...+ m*3 = 3*(1 + 2 +...+ m)
where
m = n/3
1 + 2 +...+ m is the sum of an algorithmic expression, given by:
m*(1+m)/2
We therefore can write:
def tot(x,n)
m = n/x
x*m*(1+m)/2
end
For example,
tot(3,9) #=> 18 (1*3 + 2*3 + 3*3)
tot(3,11) #=> 18
tot(3,12) #=> 30 (18 + 4*3)
tot(3,17) #=> 45 (30 + 5*3)
tot(5,9) #=> 5 (1*5)
tot(5,10) #=> 15 (5 + 2*5)
tot(5,14) #=> 15
tot(5,15) #=> 30 (15 + 3*5)
The sum of numbers no larger than n that are multiple of 3's and 5's is therefore given by the following:
def sum_of_multiples(n)
tot(3,n) + tot(5,n) - tot(15,n)
end
- tot(15,n) is needed because the first two terms double-count numbers that are multiples of 15.
sum_of_multiples(9) #=> 23 (3 + 6 + 9 + 5)
sum_of_multiples(10) #=> 33 (23 + 2*5)
sum_of_multiples(11) #=> 33
sum_of_multiples(12) #=> 45 (33 + 4*3)
sum_of_multiples(14) #=> 45
sum_of_multiples(15) #=> 60 (45 + 3*5)
sum_of_multiples(29) #=> 195
sum_of_multiples(30) #=> 225
sum_of_multiples(1_000) #=> 234168
sum_of_multiples(10_000) #=> 23341668
sum_of_multiples(100_000) #=> 2333416668
sum_of_multiples(1_000_000) #=> 233334166668
My question was triggered by this discussion on SO, which did not lead to an answer that would really explain the issue. I am "rewriting" it here in a slightly different way, because I want to make it more clear what the real problem is and therefore hope to get an answer here.
Consider the following two Ruby expressions:
1 * a - 3
1 && a = 3
From the Ruby precedence table, we know that of the operators mentioned here, * has the highest precedence, followed by -, then by && and finally by =.
The expressions don't have parenthesis, but - as we can verify in irb, providing a suitable value for a in the first case - they are evaluated as if the bracketing were written as (1*a) - 3, respectively 1 && (a=3).
The first one is easy to understand, since * binds stronger than -.
The second one can't be explained in this way. && binds stronger than =, so if precedence only would matter, the interpretation should be (1 && a) = 3.
Associativity (= is right-associative and - is left-associative) can't explain the effect either, because associativity is only important if we have several operators of the same kind (such as x-y-z or x=y=z).
There must be some special rule in the assignment operator, which I did not find in the docs I checked in particular the docs for assignment and syntax.
Could someone point out, where this special behaviour of the assignment operator is documented? Or did I miss / misunderstand something here?
From the doc: https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html#assign
Assignment expression are used to assign objects to the variables or such. Assignments sometimes work as declarations for local variables or class constants. The left hand side of the assignment expressions can be either:
variables
variables `=' expression
On the right there is an expression, so the result of the expression is assigned to the variable.
So, you should look for expressions (*) before following the precedence.
1 && a = 3 are basically two "chained" expressions:
3 and 1 && 3
Maybe it is more readable as:
1 && a = 3 + 4 where the expressions are 3 + 4 and 1 && 7, see:
1 && a = 3 + 4 #=> 7
1 && 7 #=> 7
res = 1 && a = 3 + 4
res #=> 7
(*) The precedence table also helps to find the expression (Find the precedence table in the linked doc at the Operator expressions paragraph):
What's above the = in the table "forms" an expression to be assigned by =, what's below does not.
For example:
1 + 3 and 2 + 4 #=> 4
a = 1 + 3 and b = 2 + 4 #=> 4
(a = 1 + 3) and (b = 2 + 4) #=> 4
a = (1 + 3 and b = 2 + 4) #=> 6
You can also check these examples respect to the precedence table:
1 && 3 #=> 3
1 && a = 3 #=> 3
a #=> 3
3 and 1 #=> 3
3 and b = 1 #=> 3
b #=> 1
2 ** c = 2 + 1 #=> 8
c #=> 3
d = 2 ** 3
d #=> 8
e = 3
e **= 2
e #=> 9
I think the understanding of 1 && (a = 3) is, understandably, mislead.
a = false
b = 1
b && a = 3
b
=> 1
a
=> 3
Why is a being assigned to in the && expression when a is false? Should the && expression not return when encountering a false value? Spoiler, it does return!
Taking a step back, we think of the purpose of the && operator to control the flow of logic. Our disposition to the statement
1 && a = 3
is to assume the entire statement is returned if a is nil or false. Well no, the interpreter is evaluating like so:
(1 && a) = 3
The interpreter does not raise a if it is nil or false nor does it return the left side if a is nil or false
a = nil
1 && a
=> nil # a was returned
The interpreter returns the variable, this is why the original statement can be read:
a = 3
due to 1 && a returning a which is a variable that can be assigned to by the = operand on the second half of the statement.
TLDR
In your origin example: 1 is neither nil nor false so the variable a is returned in (1 && a) which is subsequently assigned in a = 3
Probably because the other interpretation does not work:
irb(main):003:0> (1 && a) = 3
Traceback (most recent call last):
3: from /home/w/.rbenv/versions/2.7/bin/irb:23:in `<main>'
2: from /home/w/.rbenv/versions/2.7/bin/irb:23:in `load'
1: from /home/w/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):3: syntax error, unexpected '=', expecting `end')
(1 && a) = 3
^
So, perhaps Ruby parenthesizes 1 && a = 3 in the only way that is legally interpretable by the language.
I'm doing www.eulerproject.net, the first problem:
If we list all the natural numbers below 10, that are multiples of 3
or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find
the sum of all the multiples of 3 or 5 below 1000.
The following is the code I have so far.
(3..999).to_a.select do |x|
x % 3.0 == 0 || x % 5.0 == 0
end
It would be easy to append the numbers into an array, but how can this be done by how can this be done by chaining a method onto the end of this. Something like
p start loop
do stuff
end.sum
To answer the question - yes, you can chain the method like you've shown.
(3..999).to_a.select do |x|
x % 3 == 0 || x % 5 == 0 # you don't have to use floats here, integers would work
end.inject(:+)
#=> 233168
The rule of a style guides is to NOT to chain methods to multiline do end blocks, but it is a working code.
It's the same as writing
(3..999).to_a.select { |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)
#=>233168
Array#sum is an ActiveSupport method, not Ruby's, but I think you should use Ruby's methods in eulerproject tasks.
You are summing arithmetic series, so there is no need to iterate:
def sum(n,m)
p = n/m
m*p*(1+p)/2
end
n = 999
sum(n,3) + sum(n,5) - sum(n,15)
#=> 233168
Consider:
n = 100
m = 3
p = 100/3 #=> 33
sum(100,3) = 3 + 6 + 9 +...+ 99
= 3 * (1 + 2 +...+ p)
= 3 * p(1+p)/2
We need to subtract sum(100,15) because sum(100,3) + sum(100,5) double-counts:
sum(100,15) = 15 + 30 + 45 + 60 + 75 + 90
if you want to get the sum of array, you can do like this:
(3..999).inject(0) { |sum, e| e % 3 == 0 || e % 5 == 0 ? sum += e : sum }
=> 233168
it just need once loop.
You can omit the to_a, since calling 'select' to (3..999) will still return an array regardless.
Andrey's answer is the most compact one with :
(3..999).select{ |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)
For some reason I'm getting the error undefined method '%' for 1..100:Range when I run the following code:
[1..100].each do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Any idea what's going on? Any help is much appreciated.
That's the wrong syntax for ranges.
You've made an array with 1 element, and that element is itself the range 1..100. What you've written is equivalent to [(1.100)]. You're iterating over the outer array one time, and setting x to (1..100)
You want (1..100).each, which invokes each on the range, not on an array containing the range.
By doing [1..100] you are not looping from 1 to 100 but on 1..100, which is a Range object, what you really want to do is:-
(1..100).step do |x|
if x % 3 == 0 && x % 5 == 0
puts "CracklePop"
elsif x % 3 == 0
puts "Crackle"
elsif x % 5 == 0
puts "Pop"
else
puts x
end
end
Basically, Range represents an interval, you can iterate over Range as explained here, create an array from Range as explained here and more details on range can be found here.
Just as it says. 1..100 does not have a method %. The expression (1..100) % 3 is undefined.
This question already has answers here:
What does ||= (or-equals) mean in Ruby?
(23 answers)
What does the "||=" operand stand for in ruby [duplicate]
(1 answer)
Closed 9 years ago.
I am new to Ruby.
What is the difference between || and ||=?
>> a = 6 || 4
=> 6
>> a ||= 6
=> 6
Sounds like they are the same.
||= will set the left-hand value to the right hand value only if the left-hand value is falsey.
In this case, both 6 and 4 are truthy, so a = 6 || 4 will set a to the first truthy value, which is 6.
a ||= 6 will set a to 6 only if a is falsey. That is, if it's nil or false.
a = nil
a ||= 6
a ||= 4
a # => 6
x ||= y means assigning y to x if x is null or undefined or false ; it is a shortcut to x = y unless x.
With Ruby short-circuit operator || the right operand is not evaluated if the left operand is truthy.
Now some quick examples on my above lines on ||= :
when x is undefined and n is nil:
with unless
y = 2
x = y unless x
x # => 2
n = nil
m = 2
n = m unless n
m # => 2
with =||
y = 2
x ||= y
x # => 2
n = nil
m = 2
n ||= m
m # => 2
a ||= 6 only assigns 6 if it wasn't already assigned. ( actually, falsey, as Chris said)
a = 4
a ||= 6
=> 4
a = 4 || 6
=> 4
You can expand a ||= 6 as
a || a = 6
So you can see that it use a if a is not nil or false, otherwise it will assign value to a and return that value. This is commonly used for memoization of values.
Update
Thanks to the first comment for pointing out the true expansion of the ||= (or equal) operator. I learned something new and found this interesting post that talks about it. http://dablog.rubypal.com/2008/3/25/a-short-circuit-edge-case
Both expressions a = 6 || 4 and a ||= 6 return the same result but the difference is that ||= assigns value to variable if this variable is nil or false.