This question already has answers here:
What is the Ruby <=> (spaceship) operator?
(6 answers)
Closed 9 years ago.
What is the meaning of '<==>' in Ruby?
Example: The code comes from the following class that compares numbers in the format x.x.x,
def <==>(other)
# Some code here
end
The following code comes from this class that orders numbers like x.x.x,
class Version
attr_reader :fst, :snd, :trd
def initialize(version="")
v = version.split(".")
#fst = v[0].to_i
#snd = v[1].to_i
#trd = v[2].to_i
end
def <=>(other)
return #fst <=> other.fst if ((#fst <=> other.fst) != 0)
return #snd <=> other.snd if ((#snd <=> other.snd) != 0)
return #trd <=> other.trd if ((#trd <=> other.trd) != 0)
end
def self.sort
self.sort!{|a,b| a <=> b}
end
def to_s
#sorted = #fst.to_s + "." + #snd.to_s + "." + #trd.to_s
#Puts out "#{#sorted}".
end
end
That is the spaceship operator. However, it is actually <=> (not <==>).
Although that is not its official name, I'm sure, it's the most commonly used name for that operator. It is a comparison operator where
If other is less than self, return 1,
If other is equal to self, return 0
If other is greater than self, return -1
It is a powerful operator in that by just implementing this you can do sorting of your own type and participate in a lot of other niceties, like the Enumerable mixin.
Why don't you just try it out? By just typing in the code you posted, it is trivial to see for yourself that it doesn't mean anything, since <==> is not a valid method name in Ruby. The code you posted will just raise a SyntaxError.
Related
I would like to convert a base10 number to base2 in Ruby without using the built in to_s(2) method, using recursion.
I wrote this:
def to_binary(d)
if d<1
return ""
else
return to_binary(d/2).to_s + (d%2).to_s
end
end
This would return all correct results EXCEPT 0. Is there any way to return 0 for 0 without having leading zeroes for numbers greater than 0?
You can modify your checks a bit:
def to_binary(d)
return d.to_s if [0,1].include?(d) # same as "if d == 0 || d == 1"
to_binary(d/2) + (d%2).to_s
end
to_binary(10) == "1010"
#=> true
to_binary(0) == "0"
#=> true
You could also write above method as:
def to_binary(d)
return d.to_s if [0,1].include?(d)
div,mod = d.divmod(2)
to_binary(div) + mod.to_s
end
I'm trying to write a method in Ruby that:
if the string length is even numbers it will return the middle two characters and,
if the string length is odd it will return only the middle character
i put together this code, but it is not working:
def the_middle(s)
if s.length % 2 == 0
return s.index(string.length/2-1) && s.index(string.length/2)
else
return s.index(string.length/2).round
end
end
I think the problem is in the syntax, not the logic, and I was hoping someone could identify where the syntax error might be.
I really appreciate your help!
Actually you have both syntax errors and logic (semantic) errors in that code.
First of all it seems you have misunderstood how the index method on string works. It does not return the character at the given index but the index of a given substring or regex as can be seen in the documentation:
Returns the index of the first occurrence of the given substring or pattern (regexp) in str.
You're also using the wrong operator to concatenate the two middle characters when the string length is even. && is the logical and operator. It's usually used for conditions and not assigments - for example in an if statement if s.length.even? && s.length > 2. The operator you want to use is + which concatenates strings.
Finally, you're using string.length but string is not defined anywhere. What you mean is probably s.length (the input parameter).
The correct solution would be more like the following:
def the_middle(s)
if s.length.even?
return s[s.length/2-1] + s[s.length/2]
else
return s[s.length/2]
end
end
I have taken the liberty to replace s.length % 2 == 0 with s.length.even? as it's more intention revealing and really the ruby way of finding out whether an integer is even or odd.
You can solve this without a conditional using String#[].
Using a range with a negative end:
def the_middle(s)
i = (s.length - 1) / 2
s[i..-i.succ]
end
Or start and length:
def the_middle(s)
a, b = (s.length - 1).divmod(2)
s[a, b + 1]
end
Both return the same results:
the_middle("a") #=> "a"
the_middle("aba") #=> "b"
the_middle("abcba") #=> "c"
the_middle("abcdcda") #=> "d"
# ^
the_middle("abba") #=> "bb"
the_middle("abccba") #=> "cc"
the_middle("abcddcda") #=> "dd"
# ^^
Try this:
def get_middle(s)
x = (s.length/2)
s.length.even? ? s[x-1..x] : s[x]
end
Since olerass already answered your doubt about the syntax, i will suggest you a less verbose solution for the question in the title:
def the_middle(s)
return s[s.length/2] if s.length.odd?
s[s.length/2-1] + s[s.length/2]
end
Same answer the syntax is just consolidated.
Format (logic result) ? ( if true this is the result) : (if false this is the result)
def get_middle(s)
num = s.length
num.even? ? ( s[num/2-1] + s[num/2]) : (s[num/2])
end
I have a function that generates random output (string).
I need to call that function until I get 3 different outputs (strings).
What is the most elegant way to generate array with 3 unique strings by calling the function, with the limit how many times the function can be called if the output is not generated in specified number of attempts?
Here's what I currently have:
output = []
limit_calls = 5
limit_calls.times do |i|
str = generate_output_function
output.push str
break if output.uniq.size > 2
end
Can this be beautified / shortened to 1 line? I'm pretty sure in ruby.. :)
Thanks
Using a set makes it (a bit) easier:
require 'set'
output = Set.new
limit_calls = 5
call_count = 0
while output.size < 3 and call_count < limit_calls
output << generate_output_function
call_count += 1
end
output
or with an array
output = []
limit_calls = 5
while output.size < limit_calls and output.uniq.size < 3
output << generate_output_function
end
output.uniq
UPDATE with the call limit. Seems like the Array version wins! Thanks Iain!
Will also ponder a version using inject.
UPDATE 2 - with inject:
5.times.inject([]) { |a, el| a.uniq.size < 3 ? a << generate_output_function : a }
there is your oneliner. I am not sure I prefer it cause it is a bit hard to follow.....
Froderik's answer missed out the call_limit requirement. What about a function like...
def unique_string_array(call_limit)
output = []
calls = 0
until (output.size == 3 || calls == call_limit) do
(output << generate_output_function).uniq! && calls+=1
end
output
end
It isn't a one-liner but it is readable... with this implementation, you may end up with arrays less than size 3. The most important thing is that you have a test that asserts the behaviour you want! (in order to test this thoroughly you'll have to stub out the call to generate_output_function)
I wanted to check if a string is palindrome or not using ruby code.
I am a starter in ruby so not too aquainted with the string methods in ruby
If you are not acquainted with Ruby's String methods, you should have a look at the documentation, it's very good. Mithun's answer already showed you the basic principle, but since you are new to Ruby, there's a couple more things to keep in mind:
*) If you have a predicate method, it's customary to name it with a trailing question mark, e.g. palindrome?.
*) Boolean expressions evaluate to a boolean, so you don't need to explicitly return true or false. Hence a short idiomatic version would be
def palindrome?(str)
str == str.reverse
end
*) Since Ruby's classes are open, you could add this to the string class:
class String
def palindrome?
self == self.reverse
end
end
*) If you don't want to monkey-patch String, you can directly define the method on single object (or use a module and Object#extend):
foo = "racecar"
def foo.palindrome?
self == self.reverse
end
*) You might want to make the palindrome check a bit more complex, e.g. when it comes to case or whitespace, so you are also able to detect palindromic sentences, capitalized words like "Racecar" etc.
pal = "Never a foot too far, even."
class String
def palindrome?
letters = self.downcase.scan(/\w/)
letters == letters.reverse
end
end
pal.palindrome? #=> true
def check_palindromic(variable)
if variable.reverse == variable #Check if string same when reversed
puts "#{ variable } is a palindrome."
else # If string is not the same when reversed
puts "#{ variable } is not a palindrome."
end
end
The recursive solution shows how strings can be indexed in Ruby:
def palindrome?(string)
if string.length == 1 || string.length == 0
true
else
if string[0] == string[-1]
palindrome?(string[1..-2])
else
false
end
end
end
If reading the Ruby string documentation is too boring for you, try playing around with the Ruby practice questions on CodeQuizzes and you will pick up most of the important methods.
def is_palindrome(value)
value.downcase!
# Reverse the string
reversed = ""
count = value.length
while count > 0
count -= 1
reversed += value[count]
end
# Instead of writing codes for reverse string
# we can also use reverse ruby method
# something like this value == value.reverse
if value == reversed
return "#{value} is a palindrom"
else
return "#{value} is not a palindrom"
end
end
puts "Enter a Word"
a = gets.chomp
p is_palindrome(a)
class String
def palindrome?
self.downcase == self.reverse.downcase
end
end
puts "racecar".palindrome? # true
puts "Racecar".palindrome? # true
puts "mississippi".palindrome? # false
str= gets.chomp
str_rev=""
n=1
while str.length >=n
str_rev+=str[-n]
n+=1
end
if str_rev==str
puts "YES"
else
puts "NO"
end
> first method
a= "malayalam"
if a == a.reverse
puts "a is true"
else
puts "false"
end
> second one
a= "malayalam"
a=a.split("")
i=0
ans=[]
a.count.times do
i=i+1
k=a[-(i)]
ans << k
end
if a== ans
puts "true"
else
puts "false"
end
def palindrome?(string)
string[0] == string[-1] && (string.length <= 2 || palindrome?(string[1..-2]))
end
**Solution 1** Time complexity = O(n), Space complexity = O(n)
This solution does not use the reverse method of the String class. It uses a stack(we could use an array that only allows entry and exit of elements from one end to mimic a stack).
def is_palindrome(str)
stack = []
reversed_str = ''
str.each_char do |char|
stack << char
end
until stack.empty?
reversed_str += stack.pop
end
if reversed_str == str
return true
else
return false
end
end
` Solution 2: Time complexity = O(n), Space complexity = O(1)
def inplace_reversal!(str)
i =0
j = str.length - 1
while i < j
temp = str[i]
str[i] = str[j]
str[j] = temp
i+=1
j-=1
end
return str
end
def palindrome?(str)
return "Please pass the string" if str.nil?
str = str.downcase
str_array = str.split('')
reverse_string = str_array.each_index{ |index| str_array[str_array.count - index - 1 ] end
return ("String #{str} is not a palindrome") unless str == reverse_string.join('')
"String #{str} is palindrome"
end
My apologies if this has been answered before or is obvious...did some searching here and on the Goog and couldn't find an answer.
I'm looking to sort an array of Providers by price and whether they are a preferred_provider? (true or false)
For instance in array p of Providers...
p1.price == 1, p1.preferred_provider? == false
p2.price == 2, p2.preferred_provider? == true
p2.price == 3, p3.preferred_provider? == true
I would like to p.sort_by and get:
[p2 p3 p1]
IAW
p.sort_by {|x| x.preferred_provider?, x.price }
does not work and gets...
undefined method `<=>' for false:FalseClass
Any suggestions on better ways to approach this problem?
Most languages provide sort functions that accept comparators for this sort of thing. In Ruby, this is just array.sort:
p.sort {|a, b| if (a.preferred_provider? == b.preferred_provider?
then a.price <=> b.price
elsif a.preferred_provider?
1
else -1
}
You could define a <=> on the Provider class to do what you want, and then sort using the Array.sort method (rather than Enumerable.sort_by). Here's a definition of <=> that I whipped up:
class Provider
def <=>(other)
if preferred_provider?
if other.preferred_provider?
#price <=> other.price
else
1
end
else
if other.preferred_provider?
-1
else
#price <=> other.price
end
end
end
end
Then, if you have your array p, you could just do p_sorted = p.sort.
(Note that I haven't tested this code, so there may be a few errors, but I think it serves to demonstrate the idea.)