Simple way to test if multiple variables have same value, ruby - ruby

Is there a simple way of testing that several variables have the same value in ruby?
Something linke this:
if a == b == c == d #does not work
#Do something because a, b, c and d have the same value
end
Of course it is possible to check each variable against a master to see if they are all true, but that is a bit more syntax and is not as clear.
if a == b && a == c && a == d #does work
#we have now tested the same thing, but with more syntax.
end
Another reason why you would need something like this is if you actually do work on each variable before you test.
if array1.sort == array2.sort == array3.sort == array4.sort #does not work
#This is very clear and does not introduce unnecessary variables
end
#VS
tempClutter = array1.sort
if tempClutter == array2.sort && tempClutter == array3.sort && tempClutter == array4.sort #works
#this works, but introduces temporary variables that makes the code more unclear
end

Throw them all into an array and see if there is only one unique item.
if [a,b,c,d].uniq.length == 1
#I solve almost every problem by putting things into arrays
end
As sawa points out in the comments .one? fails if they are all false or nil.

tokland suggested a very nice approach in his comment to a similar question:
module Enumerable
def all_equal?
each_cons(2).all? { |x, y| x == y }
end
end
It's the cleanest way to express this I've seen so far.

How about:
[a,b,c,d] == [b,c,d,a]
Really just:
[a,b,c] == [b,c,d]
will do

a = [1,1,1]
(a & a).size == 1 #=> true
a = [1,1,2]
(a & a).size == 1 #=> false

[b, c, d].all?(&a.method(:==))

Related

Combining multiple 'elsif' statements

I try to programm snakes in Ruby. In order to get myself more familiar with Ruby. I define the position of every part of the snake through saving its X and Y value in two 1D arrays one for a X value and one for a Y value.
$x = [2,...]
$y = [2,...]
(What I forgot to tell is that the head of the Snake moves through user input while the rest just inherits its position from the part before like this.)
def length(f)
if $length >= f
$y[f] = $y[f-1]
$x[f] = $x[f-1]
end
end
In order to get a field for the Snake to move around I programmed this.
for a in (1..20)
for b in (1..20)
print " X "
end
puts" "
end
Which gives me a 20*20 field.
I then tried to display every part of the snake like on the field like this.(While also drawing a boarder around the field.)
for a in (1..20)
for b in (1..20)
if a == 1 || a == 20
if b == 1 || b == 20
print " + "
else
print " - "
end
elsif b == 1 || b == 20
print " | "
elsif a == $x[0] && b == $y[0]
body
elsif a == $x[1] && b == $y[1]
body
elsif a == $x[2] && b == $y[2]
body
elsif a == $x[3] && b == $y[3]
body
elsif a == $x[4] && b == $y[4]
body
else
print " "
end
end
puts""
end
This works but if the user is really good/ has a lot of spare time I need to make allot of elsif for every one represents a part of the snake if the snake should have as a limit a length of 100 I would need to make 100 elsif statements.(The body is just:
def body
print " # ".green
end
)
I tried fixing it with a for loop like this:
for c in (1..100)
if a == $x[c] && b == $y[c]
body
end
end
and this
loop do
$x.size.times do |index|
if $x[index] == a && $y[index] == b
body
end
end
break
end
But sadly this didn't gave the desired outcome for this interfered with the ifthat draws the boarders of the field.
Is there a way to combine these multiple elsif statements?
Every help would be highly appreciated. ( Sorry for being to vague in the first draft.)
Recommended Refactorings
NB: You included no sample data in your original post, so your mileage with answers will vary.
You have a number of issues, not just one. Besides not being DRY, your code is also not very testable because it's not broken out into discrete operations. There are a number of things you can (and probably should) do:
Break your "body" stuff into discrete methods.
Use Array or Enumerator methods to simplify the data.
Use dynamic methods to loop over your arrays, rather than fixed ranges or for-loops.
Use case/when statements inside your loop to handle multiple conditionals for the same variable.
In short, you need to refactor your code to be more modular, and to leverage the language to iterate over your data objects rather than using one conditional per element as you're currently doing.
Simplify Your Data Set and Handle Procedurally
As an example, consider the following:
def handle_matched_values array
end
def handle_mismatched_values array
end
paired_array = a.zip b
matched_pairs = paired_array.select { |subarray| subarray[0] == subarray[1] }
unmatched_pairs = paired_array.reject { |subarray| subarray[0] == subarray[1] }
matched_pairs.each { |pair| handle_matched_values pair }
matched_pairs.each { |pair| handle_mismatched_values pair }
In this example, you may not even need an if statement. Instead, you could use Array#select or Array#reject to find indices that match whatever criteria you want, and then call the relevant handler for the results. This has the advantage of being very procedural, and makes it quite clear what data set and handler are being paired. It's also quite readable, which is extremely important.
Dynamic Looping and Case Statements
If you truly need to handle your data within a single loop, use a case statement to clean up your conditions. For example:
# Extract methods to handle each case.
def do_something_with data; end
def do_something_else_with data; end
def handle_borders data; end
# Construct your data any way you want.
paired_array = a.zip b
# Loop over your data to evaluate each pair of values.
paired_array.each do |pair|
case pair
when a == b
do_something_with pair
when a == paired_array.first || paired_array.last
handle_borders pair
else
do_something_else_with pair
end
end
There are certainly plenty of other ways to work pairwise with a large data set. The goal is to give you a basic structure for refactoring your code. The rest is up to you!
I would start with something like this:
(1..20).each do |a|
(1..20).each do |b|
if [1, 20].include?(a)
print([1, 20].include?(b) ? ' + ' : ' - ')
elsif (1..100).any? { |i| a == $x[i] && b == $y[i] }
body
else
print(' ')
end
puts('')
end
end
I suppose this would work as a solution even if it is not that advanced?
loop do
$x.size.times do |index|
if $x[index] == a && $y[index] == b
body
end
end
break
end

Ruby Multiple AND Evaluations For Integer Value

I have, on a few occasions, found myself needing to write a rather verbose if statement in some ruby scripts.
The statement would look something like this:
if long_var_name == 0 && very_different_name == 0 && other_third_var == 0 && additional_variable == 0 && name_five == 0 && longest_variable_name_six == 0
# (possibly even more conditions)
# do stuff here...
end
It seems like there has to be a more elegant way to do this.
The problem is, if and and aren't exactly easy to research with google, as basic english words. So I've come up empty-handed.
Does anyone know a way to shorten this kind of situation?
It can become a nightmare to read when you have even more of them.
Sometimes variable renaming isn't an option.
The names are sometimes vastly different.
Note: I found a clever solution for similar situations with OR:
Ruby Multiple OR Evaluations For String Value
If you have an array and are specifically testing for zero, you can do:
vars1 = [0,0,3,0,0]
vars2 = [0,0,0,0,0]
vars1.all?(&:zero?) # false
vars2.all?(&:zero?) # true
EDIT: Based on OP's added conditions of having different names for the values:
if [long_var_name_1,long_var_name_2,long_var_name_3].all?(&:zero?)
# do stuff here...
end
In your specific case, I would write
if [a, b, c, d, e, f].all? { |var| var == 0 }
There's noting wrong about chaining and conditions IMHO.
Have you thought of breaking it up into logic expressions? Basically break it up into smaller bits of logical groupings and its easier to read e.g.
grp_1_zero = var_1 == 0 && var_2 == 0 && var_3 == 0
grp_2_zero = var_a == 0 && var_b == 0 && var_c == 0
grp_3_zero = var_z == 0 && var_x == 0 && var_y == 0
if grp_1_zero && grp_2_zero && grp_3_zero
#code here
end
Another, for array a:
a == Array.new(a.size,0)
You can use Enumerable#all? and the Symbol#to_proc utilisation of the Fixnum#zero? method.
foo = 0
bar = 0
baz = 0
[foo, bar, baz].all? &:zero?
# => true
one = 1
two = 2
[foo, one, two].any? &:zero?
#=> true
Note that you can also provide any anonymous function for the test.
owns_peanuts = ->(person){ person.inventory.contains :peanuts }
[bill, david, mike].any? &owns_peanuts

Can an "if (a == b || c == b)" statement be done shorter in Ruby

I have a piece of code in Ruby which goes as follows:
def check
if a == b || c == b
# execute some code
# b = the same variable
end
end
can this be written like
def check
if a || c == b
# this doesn't do the trick
end
if (a || c) == b
# this also doesn't do the magic as I thought it would
end
end
Or in a manner where I don't need to type b twice. This is out of laziness and I would like to know.
if [a, c].include? b
# code
end
This is, however, significantly slower than the code you want to avoid -- at least as long as a, b and c are basic data. My measurements showed a factor of 3. This is probably due to the additional Array object creation. So you might have to weigh DRY against performance here. Normally it should not matter, though, because both variants do not take long.
While not an exact equivalent of a == b || a == c, case statement offers syntax for this:
case a
when b, c then puts "It's b or c."
else puts "It's something else."
end
Feel free to opent the nearest Ruby textbook and read about how case statement works. Spoiler: It works by calling #=== method on the compared objects:
a = 42
b, c = Object.new, Object.new
def b.=== other; puts "b#=== called" end
def c.=== other; puts "c#=== called" end
Now run
case a
when b, c then true
else false end
This gives you a lot of flexibility. It requires work in the back office, but after you do it, looks like magic in the front office.
You should really know why this doesn't work:
(a || c) == b
This seems like a translation of the sentence "a or c is equal b", which makes sense in English.
In almost all programming languages, (a || c) is an expression, whose evaluated result will be compared to b. The translation to English is "The result of the operation "a or c" is equal to b".
#undur_gongor's answer is perfectly correct. Just to add though, if you're working with arrays, for example:
a = [1,2,3]
c = [4,5,6]
b = [5,6]
if [a, c].include? b
# won't work if your desired result is true
end
You'd have to do something like:
if [a,c].any?{ |i| (i&b).length == b.length }
# assuming that you're always working with arrays
end
# otherwise ..
if [a,c].any?{ |i| ([i].flatten&[b].flatten).length == [b].flatten.length }
# this'll handle objects other than arrays too.
end
What about this?
if [a,c].index(b) != nil;puts "b = a or b = c";end
Acolyte pointed out you can use b == (a||c), you just had it backwards, but that only works for the left value, since (a||c) is always a, assuming a isn't falsey.
Another option is to use a ternary operator.
a==b ? true : b==c
I'm not sure of the speed difference cited wrt the array approach, but I would think this could be faster since it's doing either one or two comparisons and doesn't need to deal with arrays. Also, I assume it's the exact same as (a==b || b==c), but it's a stylistic alternative.

Solving Fizzbuzz Using Rubys Enumerable Module?

Hey I was given the fizzbuzz task recently and I had answered with the usual,
if ((i%3==0) || (i.to_s.include?('3'))) && ((i%7==0) || (i.to_s.include?('7')))
p 'Fizzbuzz'
elsif (i%3==0) || (i.to_s.include?('3'))
p 'Fizz'
elsif (i%7==0) || (i.to_s.include?('7'))
p 'Buzz'
else
p i
end
and when asked to shorten it I tried using ternary operators:
p (i%3<1 || i.to_s.include?('3')) ? ((i%7<1 || i.to_s.include?('7')) ? "Fizzbuzz" : "Fizz") : ((i%7<1 || i.to_s.include?('7')) ? "Buzz" : i)
but when asked to solve it using the Enumerable methods(select,reject,collect etc) I was well stumped...Any body tried this before??
The select/collect methods were specificaly mentioned so I'm guessing that he had something like this in mind(excuse the crappy code)
(1..100).select { |i| i % 3 == 0 }.collect { "fizz" }
but i'm stuck when trying to do this for the 3 conditions and print out the result(ie iterate through the output array) :\
Probably not much help now, but I've produced a gem (fizzbuzzard) that monkey patches Fixnum such that all multiples of three print as Fizz, all multiples of five etc etc. Interviewers will respect you for using your knowledge of existing libraries rather than pointlessly re-solving solved problems.
Get it from rubgems here and find the source here.
The part I'm proudest of? The test suite. Output reproduced here:
(0h8m|master) [fizzbuzzard] $ rspec
.
Finished in 0 seconds
1 example, FIZZBUZZ failures
def fizzbuzz(i)
[nil,nil,"Fizz",nil, nil,nil,"Buzz"].each_with_index do |fizz_or_buzz, idx|
print fizz_or_buzz if (i.to_i % (1+idx)).zero?
end
end
If the interviewer doesn't laugh, then it's probably not going to be a good fit (for me anyways).
Note that print doesn't add a newline (vs p)
See http://rosettacode.org/wiki/FizzBuzz#Ruby for more common solutions.
This one's a little dense but fun. It abuses arrays and some functional methods slightly to avoid using any if statements.
rules = {
3 => ["fizz"],
7 => ["buzz"]
}
(1..100).map do |n|
[rules.map do |key, value|
value[n % key]
end.compact.join, n.to_s].find do |word|
!word.empty?
end
end.join("\n")
It is not clean to repeat the same conditionals.
p case [
i.%(3).zero? || i.to_s.include?("3"),
i.%(7).zero? || i.to_s.include?("7")
]
when [true, true] then "Fizzbuzz"
when [true, false] then "Fizz"
when [false, true] then "Buzz"
when [false, false] then i
end
This hands you back the results in an array of strings, you can do whatever you want with them at that point.
results = (1..100).to_a.collect do |i|
f = ((i%3).zero? || i.to_s.include?('3'))
b = ((i%7).zero? || i.to_s.include?('7'))
"#{:fizz if f}#{:buzz if b}#{i unless f || b}"
end
p results

What does ||= (or-equals) mean in Ruby?

What does the following code mean in Ruby?
||=
Does it have any meaning or reason for the syntax?
a ||= b is a conditional assignment operator. It means:
if a is undefined or falsey, then evaluate b and set a to the result.
Otherwise (if a is defined and evaluates to truthy), then b is not evaluated, and no assignment takes place.
For example:
a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0
foo = false # => false
foo ||= true # => true
foo ||= false # => true
Confusingly, it looks similar to other assignment operators (such as +=), but behaves differently.
a += b translates to a = a + b
a ||= b roughly translates to a || a = b
It is a near-shorthand for a || a = b. The difference is that, when a is undefined, a || a = b would raise NameError, whereas a ||= b sets a to b. This distinction is unimportant if a and b are both local variables, but is significant if either is a getter/setter method of a class.
Further reading:
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html
This question has been discussed so often on the Ruby mailing-lists and Ruby blogs that there are now even threads on the Ruby mailing-list whose only purpose is to collect links to all the other threads on the Ruby mailing-list that discuss this issue.
Here's one: The definitive list of ||= (OR Equal) threads and pages
If you really want to know what is going on, take a look at Section 11.4.2.3 "Abbreviated assignments" of the Ruby Language Draft Specification.
As a first approximation,
a ||= b
is equivalent to
a || a = b
and not equivalent to
a = a || b
However, that is only a first approximation, especially if a is undefined. The semantics also differ depending on whether it is a simple variable assignment, a method assignment or an indexing assignment:
a ||= b
a.c ||= b
a[c] ||= b
are all treated differently.
Concise and complete answer
a ||= b
evaluates the same way as each of the following lines
a || a = b
a ? a : a = b
if a then a else a = b end
-
On the other hand,
a = a || b
evaluates the same way as each of the following lines
a = a ? a : b
if a then a = a else a = b end
-
Edit: As AJedi32 pointed out in the comments, this only holds true if: 1. a is a defined variable. 2. Evaluating a one time and two times does not result in a difference in program or system state.
In short, a||=b means: If a is undefined, nil or false, assign b to a. Otherwise, keep a intact.
Basically,
x ||= y means
if x has any value leave it alone and do not change the value, otherwise
set x to y
It means or-equals to. It checks to see if the value on the left is defined, then use that. If it's not, use the value on the right. You can use it in Rails to cache instance variables in models.
A quick Rails-based example, where we create a function to fetch the currently logged in user:
class User > ActiveRecord::Base
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
end
It checks to see if the #current_user instance variable is set. If it is, it will return it, thereby saving a database call. If it's not set however, we make the call and then set the #current_user variable to that. It's a really simple caching technique but is great for when you're fetching the same instance variable across the application multiple times.
To be precise, a ||= b means "if a is undefined or falsy (false or nil), set a to b and evaluate to (i.e. return) b, otherwise evaluate to a".
Others often try to illustrate this by saying that a ||= b is equivalent to a || a = b or a = a || b. These equivalencies can be helpful for understanding the concept, but be aware that they are not accurate under all conditions. Allow me to explain:
a ||= b ⇔ a || a = b?
The behavior of these statements differs when a is an undefined local variable. In that case, a ||= b will set a to b (and evaluate to b), whereas a || a = b will raise NameError: undefined local variable or method 'a' for main:Object.
a ||= b ⇔ a = a || b?
The equivalency of these statements are often assumed, since a similar equivalence is true for other abbreviated assignment operators (i.e. +=,-=,*=,/=,%=,**=,&=,|=,^=,<<=, and >>=). However, for ||= the behavior of these statements may differ when a= is a method on an object and a is truthy. In that case, a ||= b will do nothing (other than evaluate to a), whereas a = a || b will call a=(a) on a's receiver. As others have pointed out, this can make a difference when calling a=a has side effects, such as adding keys to a hash.
a ||= b ⇔ a = b unless a??
The behavior of these statements differs only in what they evaluate to when a is truthy. In that case, a = b unless a will evaluate to nil (though a will still not be set, as expected), whereas a ||= b will evaluate to a.
a ||= b ⇔ defined?(a) ? (a || a = b) : (a = b)????
Still no. These statements can differ when a method_missing method exists which returns a truthy value for a. In this case, a ||= b will evaluate to whatever method_missing returns, and not attempt to set a, whereas defined?(a) ? (a || a = b) : (a = b) will set a to b and evaluate to b.
Okay, okay, so what is a ||= b equivalent to? Is there a way to express this in Ruby?
Well, assuming that I'm not overlooking anything, I believe a ||= b is functionally equivalent to... (drumroll)
begin
a = nil if false
a || a = b
end
Hold on! Isn't that just the first example with a noop before it? Well, not quite. Remember how I said before that a ||= b is only not equivalent to a || a = b when a is an undefined local variable? Well, a = nil if false ensures that a is never undefined, even though that line is never executed. Local variables in Ruby are lexically scoped.
If X does NOT have a value, it will be assigned the value of Y. Else, it will preserve it's original value, 5 in this example:
irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5
# Now set x to nil.
irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10
x ||= y
is
x || x = y
"if x is false or undefined, then x point to y"
||= is a conditional assignment operator
x ||= y
is equivalent to
x = x || y
or alternatively
if defined?(x) and x
x = x
else
x = y
end
unless x
x = y
end
unless x has a value (it's not nil or false), set it equal to y
is equivalent to
x ||= y
Suppose a = 2 and b = 3
THEN, a ||= b will be resulted to a's value i.e. 2.
As when a evaluates to some value not resulted to false or nil.. That's why it ll not evaluate b's value.
Now Suppose a = nil and b = 3.
Then a ||= b will be resulted to 3 i.e. b's value.
As it first try to evaluates a's value which resulted to nil.. so it evaluated b's value.
The best example used in ror app is :
#To get currently logged in iser
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
# Make current_user available in templates as a helper
helper_method :current_user
Where, User.find_by_id(session[:user_id]) is fired if and only if #current_user is not initialized before.
||= is called a conditional assignment operator.
It basically works as = but with the exception that if a variable has already been assigned it will do nothing.
First example:
x ||= 10
Second example:
x = 20
x ||= 10
In the first example x is now equal to 10. However, in the second example x is already defined as 20. So the conditional operator has no effect. x is still 20 after running x ||= 10.
a ||= b
Signifies if any value is present in 'a' and you dont want to alter it the keep using that value, else if 'a' doesnt have any value, use value of 'b'.
Simple words, if left hand side if not null, point to existing value, else point to value at right side.
a ||= b
is equivalent to
a || a = b
and not
a = a || b
because of the situation where you define a hash with a default (the hash will return the default for any undefined keys)
a = Hash.new(true) #Which is: {}
if you use:
a[10] ||= 10 #same as a[10] || a[10] = 10
a is still:
{}
but when you write it like so:
a[10] = a[10] || 10
a becomes:
{10 => true}
because you've assigned the value of itself at key 10, which defaults to true, so now the hash is defined for the key 10, rather than never performing the assignment in the first place.
It's like lazy instantiation.
If the variable is already defined it will take that value instead of creating the value again.
Please also remember that ||= isn't an atomic operation and so, it isn't thread safe. As rule of thumb, don't use it for class methods.
This is the default assignment notation
for example: x ||= 1
this will check to see if x is nil or not. If x is indeed nil it will then assign it that new value (1 in our example)
more explicit:
if x == nil
x = 1
end
b = 5
a ||= b
This translates to:
a = a || b
which will be
a = nil || 5
so finally
a = 5
Now if you call this again:
a ||= b
a = a || b
a = 5 || 5
a = 5
b = 6
Now if you call this again:
a ||= b
a = a || b
a = 5 || 6
a = 5
If you observe, b value will not be assigned to a. a will still have 5.
Its a Memoization Pattern that is being used in Ruby to speed up accessors.
def users
#users ||= User.all
end
This basically translates to:
#users = #users || User.all
So you will make a call to database for the first time you call this method.
Future calls to this method will just return the value of #users instance variable.
As a common misconception, a ||= b is not equivalent to a = a || b, but it behaves like a || a = b.
But here comes a tricky case. If a is not defined, a || a = 42 raises NameError, while a ||= 42 returns 42. So, they don't seem to be equivalent expressions.
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1
Because a was already set to 1
irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2
Because a was nil
This ruby-lang syntax. The correct answer is to check the ruby-lang documentation. All other explanations obfuscate.
Google
"ruby-lang docs Abbreviated Assignment".
Ruby-lang docs
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
a ||= b is the same as saying a = b if a.nil? or a = b unless a
But do all 3 options show the same performance? With Ruby 2.5.1 this
1000000.times do
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
end
takes 0.099 Seconds on my PC, while
1000000.times do
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
end
takes 0.062 Seconds. That's almost 40% faster.
and then we also have:
1000000.times do
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
end
which takes 0.166 Seconds.
Not that this will make a significant performance impact in general, but if you do need that last bit of optimization, then consider this result.
By the way: a = 1 unless a is easier to read for the novice, it is self-explanatory.
Note 1: reason for repeating the assignment line multiple times is to reduce the overhead of the loop on the time measured.
Note 2: The results are similar if I do a=nil nil before each assignment.

Resources