I want to test whether a equals 1 or 2
I could do
a == 1 || a == 2
but this requires repeating a (which would be annoying for longer variables)
I'd like to do something like a == (1 || 2), but obviously this won't work
I could do [1, 2].include?(a), which is not bad, but strikes me as a bit harder to read
Just wondering how do to this with idiomatic ruby
Your first method is idiomatic Ruby. Unfortunately Ruby doesn't have an equivalent of Python's a in [1,2], which I think would be nicer. Your [1,2].include? a is the nearest alternative, and I think it's a little backwards from the most natural way.
Of course, if you use this a lot, you could do this:
class Object
def member_of? container
container.include? self
end
end
and then you can do a.member_of? [1, 2].
I don't know in what context you're using this in, but if it fits into a switch statement you can do:
a = 1
case a
when 1, 2
puts a
end
Some other benefits is that when uses the case equality === operator, so if you want, you can override that method for different behavior. Another, is that you can also use ranges with it too if that meets your use case:
when 1..5, 7, 10
One way would be to petition "Matz" to add this functionality to the Ruby specification.
if input == ("quit","exit","close","cancel") then
#quit the program
end
But the case-when statement already lets you do exactly that:
case input when "quit","exit","close","cancel" then
#quit the program
end
When written on one line like that, it acts and almost looks like an if statement. Is the bottom example a good temporary substitution for the top example? You be the judge.
First put this somewhere:
class Either < Array
def ==(other)
self.include? other
end
end
def either(*these)
Either[*these]
end
Then, then:
if (either 1, 2) == a
puts "(i'm just having fun)"
end
You can just use intersection like
([a] & [1,2]).present?
a alternative way.
Include is definitely the way to go here. 🤝
%w[cat dog].include?(type)
a.to_s()=~/^(1|2)$/
Maybe I'm being thick here, but it seems to me that:
(1..2) === a
...works.
Related
I was trying to make my bubble sort shorter and I came up with this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
sorted = each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end until sorted
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end
I don't particularly like the thing with sorted = --sort code-- until sorted.
I just want to run the each_index.each_cons(s).none? code until it returns true. It's a weird situation that I use until, but the condition is a code I want to run. Any way, my try seems awkward, and ruby usually has a nice concise way of putting things. Is there a better way to do this?
This is just my opinion
have you ever read the ruby source code of each and map to understand what they do?
No, because they have a clear task expressed from the method name and if you test them, they will take an object, some parameters and then return a value to you.
For example if I want to test the String method split()
s = "a new string"
s.split("new")
=> ["a ", " string"]
Do you know if .split() takes a block?
It is one of the core ruby methods, but to call it I don't pass a block 90% of the times, I can understand what it does from the name .split() and from the return value
Focus on the objects you are using, the task the methods should accomplish and their return values.
I read your code and I can not refactor it, I hardly can understand what the code does.
I decided to write down some points, with possibility to follow up:
1) do not use the proc for now, first get the Object Oriented code clean.
2) split bubble_sort! into several methods, each one with a clear task
def ordered_inverted! (bubble_sort!), def invert_values, maybe perform a invert_values until sorted, check if existing methods already perform this sorting functionality
3) write specs for those methods, tdd will push you to keep methods simple and easy to test
4) If those methods do not belong to the Array class, include them in the appropriate class, sometimes overly complicated methods are just performing simple String operations.
5) Reading books about refactoring may actually help more then trying to force the usage of proc and functional programming when not necessary.
After looking into it further I'm fairly sure the best solution is
loop do
break if condition
end
Either that or the way I have it in the question, but I think the loop do version is clearer.
Edit:
Ha, a couple weeks later after I settled for the loop do solution, I stumbled into a better one. You can just use a while or until loop with an empty block like this:
while condition; end
until condition; end
So the bubble sort example in the question can be written like this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
until (each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end); end
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end
When programming ruby I always find myself doing this:
a = [a, b].min
This means compare a and b and store the smallest value in a. I don't like writing the code above as I have to write a twice.
I know that some non-standard dialects of C++ had an operator which did exactly this
a <?= b
Which I find very convenient. But I'm not really interested in the operator as much as I'm in the feature of avoiding repetition. I would also be happy if I could write
a.keep_max(b)
a can be a quite long variable, like my_array[indice1][indice2], and you don't want to write that twice.
I did alot of googling on this and found no result, hopefully this question will pop up and be useful for others aswell.
So, is there any non-repeitive way to express what I want in ruby?
What you would like to do is in fact not possible in ruby (see this question). I think the best you can do is
def max(*args)
args.max
end
a = max a, b
I don't understand your question. You can always do something like this ...
module Comparable
def keep_min(other)
(self <=> other) <= 0 ? self : other
end
def keep_max(other)
(self <=> other) >= 0 ? self : other
end
end
1.keep_min(2)
=> 1
1.keep_max(2)
=> 2
Well, that won't work for all objects with <=> because not all of them are implementing Comparable, so you could monkey-patch Object.
Personally I prefer clarity and tend to avoid monkey-patching. Plus, this clearly is a binary predicate, just like "+", therefore method-chaining doesn't necessarily make sense so I prefer something like this to get rid of that array syntax:
def min(*args)
args.min
end
def max(*args)
args.max
end
min(1, 2)
=> 1
max(1, 2)
=> 2
But hey, I'm also a Python developer :-)
You can define your own method for it:
class Object
def keep_max(other)
[self, other].max
end
end
a = 3
b = 7
puts a.keep_max(b)
But you should be careful defining methods on Object as it can have unpredictable behaviour (for example, if objects cannot be compared).
def keep_max(var, other, binding)
eval "#{var} = [#{var}, #{other}].max", binding
end
a = 5
b = 78
keep_max(:a, :b, binding)
puts a
#=> 78
This basically does what you want. Take a look at Change variable passed in a method
I have a method that uses transpose, but I do not want to apply this operation if the array has less than 2 dimensions. I am wondering how I can do this in ruby.
so for an array like [1,2] -> it should say 1D
and for an array like [[1,2],[1,2]] it should say 2D
Any help appreciated,
Ted
You could find it recursively:
def getDimension(array)
if array.first.is_a?(Array)
1 + getDimension(array.first)
else
1
end
end
I know it is a bit crude and there probably someone who is able to make it much nicer, but the general idea is clear.
Because Ruby arrays can hold anything this is fragile and a hack at best, but you could always just check to see if the nth element is an array, i.e.,
def is_2d(array)
array.first.is_a?(Array)
end
I really don't like this, so if there is something better just slap me or downvote me into oblivion.
Hmm, I might just try #transpose and rescue IndexError, TypeError, but another idea is:
x.map(&:class).uniq == [Array]
How about
a.map{|e| e.is_a?(Array)}.uniq == [true] ? "#{e.size}D" : "1D"
module MultiDArray #this could be a subclass of Array
#if you can modify your callers
def self.transposable?(array)
array[0] && array[0][0]
end
def self.dimensions(array)
return 0 if array.nil?
return self.dimensions(array[0]) if array[0].is_a?(Array)
return 1
end
def self.dimension_to_s(array)
"#{dimensions(array)}D"
end
end
MultiDArray.transposable? #is probably what you're actually looking for.
This is presuming you're using normal ruby arrays and not Matrixes.
You've probably got worse data model problems to deal with if the arrays aren't regular, so one of these two methodologies is probably sufficient.
Don't fear errors, just anticipate them:
a.transpose rescue a
I'd like to compare multiple variables for a case statement, and am currently thinking overriding the case equals operator (===) for Array is the best way to do it. Is this the best way?
Here is an example use case:
def deposit_apr deposit,apr
# deposit: can be nil or 2 length Array of [nil or Float, String]
# apr: can be nil or Float
case [deposit,apr]
when [[Float,String],Float]
puts "#{deposit[0]} #{deposit[1]}, #{apr*100.0}% APR"
when [[nil,String],Float]
puts "#{apr*100.0}% APR on deposits greater than 100 #{deposit[1]}"
when [[Float,String],nil]
puts "#{deposit[0]} #{deposit[1]}"
else
puts 'N/A'
end
end
The only problem is the Array case equals operator doesn't apply the case equal to the elements of the Array.
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
N/A
It will if I override, but am not sure what I'd be breaking if I did:
class Array
def ===(other)
result = true
self.zip(other) {|bp,ap| result &&= bp === ap}
result
end
end
Now, it all works:
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
656.0 rupees, 6.5% APR
Am I missing something?
I found this question because I was looking to run a case statement on multiple variables, but, going through the following, came to the conclusion that needing to compare multiple variables might suggest that a different approach is needed. (I went back to my own code with this conclusion, and found that even a Hash is helping me write code that is easier to understand.)
Gems today use "no monkey patching" as a selling point. Overriding an operator is probably not the right approach. Monkey patching is great for experimentation, but it's too easy for things to go awry.
Also, there's a lot of type-checking. In a language that is designed for Duck Typing, this clearly indicates the need for a different approach. For example, what happens if I pass in integer values instead of floats? We'd get an 'N/A', even though that's not likely what we're looking for.
You'll notice that the example given in the question is difficult to read. We should be able to find a way to represent this logic more clearly to the reader (and to the writer, when they revisit the code again in a few months and have to puzzle out what's going on).
And finally, since there are multiple numbers with associated logic, it seems like there's at least one value object-type class (Deposit) that wants to be written.
For cleanliness, I'm going to assume that a nil APR can be considered a 0.0% APR.
class Deposit
def initialize(amount, unit='USD', options={})
#amount = amount.to_f # `nil` => 0.0
#unit = unit.to_s # Example assumes unit is always present
#apr = options.fetch(:apr, 0.0).to_f # `apr: nil` => 0.0
end
end
Once we have our Deposit object, we can implement the print logic without needing case statements at all.
class Deposit
# ... lines omitted
def to_s
string = "#{#amount} #{#unit}"
string << ", #{#apr * 100.0}% APR" if #apr > 0.0
string
end
end
d = Deposit.new(656.00, 'rupees', apr: 0.065)
d.to_s
# => "656.0 rupees, 6.5% APR"
e = Deposit.new(100, 'USD', apr: nil)
e.to_s
# => "100.0 USD"
f = Deposit.new(100, 'USD')
f.to_s
# => "100.0 USD"
Conclusion: If you're comparing multiple variables in a case statement, use that as a smell to suggest a deeper design issue. Multiple-variable cases might indicate that there's an object that wants to be created.
If you are worried about breaking something by changing Array behavior, and certainly that's a reasonable worry, then just put your revised operator in a subclass of Array.
it's definitely not the best way. even more - you should not redefine methods of standart classes as core functionality may depend on it - have fun debugging then.
defensive style is nice(with lot of type checks and whatnot) but it usually hurts performance and readability.
if you know that you will not pass anything else than bunch of floats and strings to that method - why do you need all those checks for?
IMO use exception catching and fix the source of problem, don't try to fix the problem somewhere in the middle
I'm trying to figure out how to check if a string matches a regular expression, but I want to know if the entire string matches just once. Here's my code but it seems absurdly long
def single_match(test_me, regex)
ret_val = false
test = regex.match(test_me)
if (test.length==1 && test[0].length == test_me.length)
ret_val = true
end
return ret_val
end
is there an easier way to do this?
P.S. Here's the method I'm really trying to write, since people always seem to ask why I want the gun these days:
def is_int(test_me)
return single_match(test_me, /[0-9]*/)
end
Edit Thanks everybody. Here's where I'm really using it, but this regex stuff is always interesting to go through. Thanks for the great and educational answers.
You don't need to do this, your method can be replaced by using the regular expression of /^[0-9]*$/. The ^ tells it match start of a line and $ tells it match end of the line. So it will match: start of line, 0 to any in range of 0 to 9, and finally end of line.
def is_int(test_me)
test_me =~ /^[0-9]*$/
end
And you don't need the return statements, Ruby implicitly returns the last statement.
Edit:
It probably would be easier and look better to use the to_i instance method of String class.
def is_int(test_me)
test_me.to_i.to_s == test_me
end
Edit: (did some tests)
Comparing the performance between the two methods shows that .to_i.to_s == way is 5% faster. So it is up to personal preference to which ever looks better and if you want to handle leading zeroes.
To do what you really want should be even simpler
def is_int(test_me)
test_me.to_i.to_s == test_me
end
This?
def single_match(str, regex)
str.match(regex).to_s == str
end
To answer your original question, for the sake of people finding this page in a search, "scan" will return an array of matches, so if you want to find out how many times some regexp matches, e.g. how many runs of digits there are, you can do:
mystring.scan(/\d+/).size