I'd like to implement a class in Ruby that's comparable (using the <=> operator) with any Fixnum, and vice-versa. This will ultimately be used in a range. Here is an outline of my class:
class N
include Comparable
attr :offset
def initialize(offset = 0)
#offset = offset
end
def succ
N.new(#offset + 1)
end
def +(offset)
N.new(#offset + offset)
end
def <=>(other)
return #offset <=> other.offset if other.kind_of? N
return 1 # N is greater than everything else
end
end
def n; N.new(0); end
Now this works great when used in n..n+2 and n..999, but not in 1..n. This is due to the fact that n <=> 1 works but 1 <=> n does not (returns nil).
Is there any way I can get Fixnum to treat my N class as a comparable object? Your thoughts are appreciated :)
If you want to implement your own number type, you must implement coerce:
class N
def coerce(other)
return N.new(other), self
end
end
n = N.new
1 <=> n # => -1
All of Ruby's builtin number types in the core library, all number types in the standard library, as well as all third-party number types use the coerce protocol to find a common type in order to make operators such as +, * and == commutative and -, / and <=> symmetric.
It's not quite clear to me what the semantics of N should be, so the above implementation is only an example.
Okay, I did a little monkey patching (freedom patching ;) that seems to have solved my problem for now.
class Fixnum
def <=>(other)
return -1 if other.kind_of? N
return -1 if self < other
return 0 if self == other
return 1 if self > other
end
end
Output seems to be as expected and it doesn't break anything in the inner workings of Fixnum as far as I can tell. Any better ideas/comments, feel free to post 'em.
1 <=> n # => -1
1 <=> 1 # => 0
1 <=> 2 # => -1
2 <=> 1 # => 1
1 == 1 # => true
1 == 2 # => false
1 < 2 # => true
1 > 2 # => false
Related
Im a bit confused at why this answer is "wrong" based on Ruby's own interpretation of the "Inject" method (for an array in this case, Im doing the "Odin Projects" projects for learning tasks)
def my_inject(start = nil)
memo = self[0] if start.nil?
for i in 0...self.length do
puts "#{memo}:#{self[i]} Results=#{yield(memo,self[i])}"
memo = yield(memo,self[i])
end
return memo
end
[5,6,7,8,9,10].my_inject { |sum, n| sum + n }
The Above returns this specifically:
5:5 Results=10
10:6 Results=16
16:7 Results=23
23:8 Results=31
31:9 Results=40
40:10 Results=50
=> 50
Which makes sense right? When no starting value is defined, the first value is used. However according to Ruby's API docs:"Inject" it should be 45....
Which doesn't make sense to me. We start with a memo of the first value and add it to the "elements" value. Which is 10 (in this case)...and so forth. Or are they saying when you DO NOT specify a value? you should skip the first array value?
I mean if I add up 5+6+7+8+9+10 yeah that is correctly 45, but if im doing what the block wants me to do, I feel like "50" makes more sense? Although obviously im wrong, im just not sure where.
I mean sure I could start the index off at 1 if we are not given a starting value...but that just seems odd.
Thanks
As people have pointed out in comments, your solution double taps the first element if no argument is provided.
Here's an implementation that is pretty straightforward, drops some unnecessary elements your solution included, and works for more than just arrays:
module Enumerable
def my_inject(memo = nil)
each { |x| memo = memo.nil? ? x : yield(memo, x) }
memo
end
end
p (1..5).my_inject(&:*) # 5 factorial => 120
p (1..5).my_inject(2, &:*) # 5 factorial doubled => 240
p %w(3 4 5).my_inject(&:+) # string concatenation => "345"
p %w(3 4 5).my_inject("hello", &:+) # concatenation w/ prefix => "hello345"
p %w(3 4 5).my_inject("howdy") { |memo, x| memo + x } # prefix and block => "howdy345"
ADDENDUM
If you want to go further and handle Symbol or String arguments as Enumerable#inject does, you need to do some preprocessing to determine what you're dealing with:
module Enumerable
def my_inject(memo = nil, sym = nil, &block)
memo = memo.to_sym if memo.is_a?(String) && !sym && !block
block, memo = memo.to_proc, nil if memo.is_a?(Symbol) && !sym
sym = sym.to_sym if sym.is_a?(String)
block = sym.to_proc if sym.is_a?(Symbol)
# Ready to rock & roll
each { |x| memo = memo.nil? ? x : block.yield(memo, x) }
memo
end
end
# A variety of test cases
p (1..4).my_inject(:*) # 4 factorial via Symbol => 24
p (1..5).my_inject('*') # 5 factorial via String => 120
p (1..6).my_inject { |memo, x| memo * x } # 6 factorial via block => 720
p (1..5).my_inject(2, &:*) # 5 factorial doubled via Proc => 240
p (1..5).my_inject(3, :*) # 5 factorial tripled via Symbol => 360
p (1..5).my_inject(4, '*') # 5 factorial quadrupled via String => 480
p %w(3 4 5).my_inject(&:+) # string concatenation via Proc => "345"
p %w(3 4 5).my_inject("hello", &:+) # prefix and Proc => "hello345"
p %w(3 4 5).my_inject("howdy") { |memo, x| memo + x } # prefix and block => "howdy345"
p %w(3 4 5).my_inject("yowza", :+) # prefix and Symbol => "yowza345"
p %w(3 4 5).my_inject("yoiks", '+') # prefix and String => "yoiks345"
I need to do round half to even on floats, i.e.,
if the value is half-way between two integers (tie-breaking, fraction part of y is exactly 0.5) round to the nearest even integer,
else, standard round (which is Round to nearest Integer in Ruby).
These are some results, for example:
0.5=>0
1.49=>1
1.5=>2
2.5=>2
2.51=>3
3.5=>4
The BigDecimal class has the rounding mode half to even already implemented. You just have to set the ROUND_MODE to :half_even with BigDecimal.mode method:
require 'bigdecimal'
def round_half_to_even(float)
BigDecimal.mode(BigDecimal::ROUND_MODE, :half_even)
BigDecimal.new(float, 0).round
end
Or by using the round with some arguments:
require 'bigdecimal'
def round_half_to_even(float)
BigDecimal.new(float, 0).round(0, :half_even).to_i
end
Please note that BigDecimal#round returns an Integer when used without arguments, but a BigDecimal when used with arguments. Therefore the need to call to_i in the second example but not in the first.
I would reopen the Float class to create a round_half_to_even function :
class Float
def round_half_to_even(precision)
if self % 1 == 0.5
floor = self.to_i.to_f
return floor % 2 == 0 ? floor : floor + 1
else
return self.round(precision)
end
end
end
def round_half_to_even f
q, r = f.divmod(2.0)
q * 2 +
case
when r <= 0.5 then 0
when r >= 1.5 then 2
else 1
end
end
round_half_to_even(0.5) # => 0
round_half_to_even(1.49) # => 1
round_half_to_even(1.5) # => 2
round_half_to_even(2.5) # => 2
round_half_to_even(2.51) # => 3
round_half_to_even(3.5) # => 4
You could do the following:
def round_half_to_even(f)
floor = f.to_i
return f.round unless f==floor+0.5
floor.odd? ? f.ceil : floor
end
round_half_to_even(2.4) #=> 2
round_half_to_even(2.6) #=> 3
round_half_to_even(3.6) #=> 4
round_half_to_even(2.5) #=> 2
round_half_to_even(3.5) #=> 4
I have this code to return true if num is a power of 2.
def is_power_of_two?(num)
result = num.inject(0) {|n1, n2| n2 ** n1}
if result == num
true
else
false
end
end
p is_power_of_two?(16)
I keep getting an error though. How could I fix and simplify this code?
Clearly, n is a non-negative integer.
Code
def po2?(n)
n.to_s(2).count('1') == 1
end
Examples
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Explanation
Fixnum#to_s provides the string representation of an integer (the receiver) for a given base. The method's argument, which defaults to 10, is the base. For example:
16.to_s #=> "16"
16.to_s(8) #=> "20"
16.to_s(16) #=> "10"
15.to_s(16) #=> "f"
It's base 2 we're interested in. For powers of 2:
1.to_s(2) #=> "1"
2.to_s(2) #=> "10"
4.to_s(2) #=> "100"
8.to_s(2) #=> "1000"
16.to_s(2) #=> "10000"
For a few natural numbers that are are not powers of 2:
3.to_s(2) #=> "11"
5.to_s(2) #=> "101"
11.to_s(2) #=> "1011"
We therefore wish to match binary strings that contain one 1.
Another Way
R = /
\A # match beginning of string ("anchor")
10* # match 1 followed by zero or more zeroes
\z # match end of string ("anchor")
/x # free-spacing regex definition mode
def po2?(n)
(n.to_s(2) =~ R) ? true : false
end
po2?(4) #=> true
po2?(5) #=> false
And one for the road
This uses Fixnum#bit_length and Fixnum#[]:
def po2?(n)
m = n.bit_length-1
n[m] == 1 and m.times.all? { |i| n[i].zero? }
end
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Try:
def is_power_of_two?(num)
num != 0 && (num & (num - 1)) == 0
end
It is well explained here (for C#, but #GregHewgill's explanation applies here as well)
I would do something like this, using Ruby's Math module.
def power_of_two?(n)
Math.log2(n) % 1 == 0
end
Or, if you wanted to be really cool:
def power_of_two?(n)
(Math.log2(n) % 1).zero?
end
Some IRB output:
2.1.0 :004 > power_of_two?(2)
=> true
2.1.0 :005 > power_of_two?(32768)
=> true
2.1.0 :006 > power_of_two?(65536)
=> true
This method assumes that the input is a positive integer.
Source
Another way to solve this is to go the other way around than most of the answers here - we can use the number 1 to start and find out if the number is the power of two. Like this:
def power_of_two?(num)
product = 1
while product < num
product *= 2
end
product == num
end
We start with 1. Then we multiply the 1 by 2, and keep multiplying by 2 until the product is larger than num (product < num). Once we hit that condition, we stop, exit the loop, and check if it's equal to num (product == num). If it is, the num is the power of 2.
As was pointed out in the comments above, you were getting errors because you're trying to use the inject method on a non-iterable (an int). Here's a solution using the suggested log2
def is_power_of_two?(num)
result = Math.log2(num)
result == Integer(result)
end
Note: will fail with very big numbers close to binaries (like 2 ^ 64 - 1). A foolproof version (but slower) would be:
def is_power_of_two?(num)
while (num % 2 == 0 and num != 0)
num /= 2
end
num == 1
end
Please comment any improvements that any of you may find.
Here is another solution that uses recursion:
def power_of_2?(number)
return true if number == 1
return false if number == 0 || number % 2 != 0
power_of_2?(number / 2)
end
In my opinion, the easiest -- but maybe a little long -- way of doing what you need to do is just writing this recursive method like so:
def power_of_two?(number)
continue = true
if number == 1
return true
end
if number % 2 != 0
return false
else
while continue == true do
if number.to_f / 2.0 == 2.0
continue = false
return true
else
if number % 2 != 0
continue = false
return false
else
number /= 2
continue = true
end
end
end
end
end
One is a power of two (2^0), so it first checks if the number given is 1. If not, it checks if it is odd, because 1 is the only odd number that is a power of two.
If it is odd it returns false and moves on to the else statement. It will check if the number divided by 2 is two, because then it would obviously be a power of 2. It does this as a float, because 5/2 in Ruby would return 2.
If that is false, it then again checks if the number is odd -- unnecessary on the first round, necessary after that. If the number is not odd, it will divide the number by two and then do the loop another time.
This will continue until the program resolves itself by getting 2 or any odd number, and returns true or false, respectively.
I ran into this one in a bootcamp application prep. I'm not a math person and don't understand a few of these methods, so I wanted to submit a common sense approach for people like me. this requires little knowledge of math, except to know a number to the second power will be the result of some number multiplied by itself.
def is_power_of_two?(num)
num.times {|n| return true if (n+1) * (n+1) == num}
false
end
this method counts up to the num variable starting at 1 and returns true if (any of those numbers in the sequence multiplied by itself) is equal to num & if num is not 0 (more on that below).
example:
num = 9
1 * 1 == 9 #=> false
2 * 2 == 9 #=> false
3 * 3 == 9 #=> true
true is returned and method is finished running.
the #times method requires an integer > 0, so this edge case is "handled" by virtue of the fact that #times does nothing with "0" as the variable and returns false when outside of the #times iteration.
def power_of_two?(num)
num.to_s(2).scan(/1/).length == 1
end
Can I measure the distance between two strings with Ruby?
I.e.:
compare('Test', 'est') # Returns 1
compare('Test', 'Tes') # Returns 1
compare('Test', 'Tast') # Returns 1
compare('Test', 'Taste') # Returns 2
compare('Test', 'tazT') # Returns 5
Much easier and fast due to native C binding:
gem install levenshtein-ffi
gem install levenshtein
require 'levenshtein'
Levenshtein.normalized_distance string1, string2, threshold
http://rubygems.org/gems/levenshtein
http://rubydoc.info/gems/levenshtein/0.2.2/frames
I found this for you:
def levenshtein_distance(s, t)
m = s.length
n = t.length
return m if n == 0
return n if m == 0
d = Array.new(m+1) {Array.new(n+1)}
(0..m).each {|i| d[i][0] = i}
(0..n).each {|j| d[0][j] = j}
(1..n).each do |j|
(1..m).each do |i|
d[i][j] = if s[i-1] == t[j-1] # adjust index into string
d[i-1][j-1] # no operation required
else
[ d[i-1][j]+1, # deletion
d[i][j-1]+1, # insertion
d[i-1][j-1]+1, # substitution
].min
end
end
end
d[m][n]
end
[ ['fire','water'], ['amazing','horse'], ["bamerindos", "giromba"] ].each do |s,t|
puts "levenshtein_distance('#{s}', '#{t}') = #{levenshtein_distance(s, t)}"
end
That's awesome output: =)
levenshtein_distance('fire', 'water') = 4
levenshtein_distance('amazing', 'horse') = 7
levenshtein_distance('bamerindos', 'giromba') = 9
Source: http://rosettacode.org/wiki/Levenshtein_distance#Ruby
There is an utility method in Rubygems that actually should be public but it's not, anyway:
require "rubygems/text"
ld = Class.new.extend(Gem::Text).method(:levenshtein_distance)
p ld.call("asd", "sdf") => 2
Much simpler, I'm a Ruby show-off at times...
# Levenshtein distance, translated from wikipedia pseudocode by ross
def lev s, t
return t.size if s.empty?
return s.size if t.empty?
return [ (lev s.chop, t) + 1,
(lev s, t.chop) + 1,
(lev s.chop, t.chop) + (s[-1, 1] == t[-1, 1] ? 0 : 1)
].min
end
Ruby 2.3 and later ship with the did_you_mean gem which includes DidYouMean::Levenshtein.distance. Fit for most cases and available by default.
DidYouMean::Levenshtein.distance("Test", "est") # => 1
I made a damerau-levenshtein gem where algorithms are implemented in C
require "damerau-levenshtein"
dl = DamerauLevenshtein
dl.distance("Something", "Smoething") #returns 1
I like DigitalRoss' solution above. However, as pointed out by dawg, its runtime grows on the order O(3^n), which is no good for longer strings.
That solution can be sped up significantly using memoization, or 'dynamic programming':
def lev(string1, string2, memo={})
return memo[[string1, string2]] if memo[[string1, string2]]
return string2.size if string1.empty?
return string1.size if string2.empty?
min = [ lev(string1.chop, string2, memo) + 1,
lev(string1, string2.chop, memo) + 1,
lev(string1.chop, string2.chop, memo) + (string1[-1] == string2[-1] ? 0 : 1)
].min
memo[[string1, string2]] = min
min
end
We then have much better runtime, (I think it's almost linear? I'm not really sure).
[9] pry(main)> require 'benchmark'
=> true
[10] pry(main)> #memo = {}
=> {}
[11] pry(main)> Benchmark.realtime{puts lev("Hello darkness my old friend", "I've come to talk with you again")}
26
=> 0.007071999832987785
let's say when I'm comparing values in ruby, i have a value in mind that no matter what I want, using sort on that value and anything else returns a -1 (so this value is default sorted as smaller than everything).
for example, let's say i want '100' to sort smaller 100% of the time against 99. so that if i'm sorting values in an array, and a comparison comes up between 100 and 99, 100 is sorted smaller (ie, -1 is returned). but, i want all the other cases to be normal (98 is smaller than 99, 50 is bigger than 30, etc)
edit: okay this is what i want
if i have an x and a y, i do not want to use
x <=> y
i want to use (in pseudocode and hand-wavy-ness)
x > y
which means, this x is always greater than this y
Why don't you instead use a dictionary to keep values associated with their relative value? In this case, the string abc can be mapped to -1, and then just make sure no other values map to values equal to or less than -1.
Edit: If you're only concerned with one particular value breaking the norm, then this solution is not for you.
Easier to handle the specialness outside of the sort!
module Enumerable
def sort_excluding(*vals)
special,rest = partition {|x| vals.include?(x)}
rest.sort + special
end
end
One way to do it would be to implement a derivative class for your custom comparisons (http://www.ruby-doc.org/core/classes/Comparable.html)
Here's some sample code (and tests) for you:
class StrA < String
include Comparable
attr :str
def <=>(anOther)
if (str == "abc" && anOther.str == "abc")
0
elsif (str == "abc")
-1
elsif (anOther.str == "abc")
1
else
str <=> anOther.str
end
end
def initialize(str)
#str = str
end
def inspect
#str
end
end
And the tests:
a = StrA.new("Z")
b = StrA.new("B")
c = StrA.new("abc")
d = StrA.new("")
a > b # 1
a > c # 1
c > a # -1
d > c # 1
c > d # -1
c < d # 1
c > d # -1
[a, b, c, d].sort! # [ "Z", "B", "", "abc"]
I think what you want is:
[30, 50, 4, 0, 100, -22, 99].sort_by {|a| [a == 100 ? -1 : 0, a ]}.reverse
which gives:
99
50
30
4
0
-22
100
Hope I understood the question!
Array#sort or Enumerable#sort(I don't know what you are trying to sort) can take an obtional block. If the block is given, the block is used for comparison instead of <=>
For example this code will sort reversed:
foo.sort { |a,b| b <=> a }
In your case you need to call #sort something like the following:
foo.sort do |a,b|
if [a,b].sort == [99,100]
b-a # returns 1 or -1 so that 99 > 100
else
a <=> b
end
end
I am not entirely sure about the way you are trying to sort, but this should enable you to use sort in the manner you need. More inforamtion about Array#sort, and any other method can be found on your linux(and possible other OS's) via ri like this: ri Array#sort.
You could override the sort method for the object like so:
class Fixnum
alias old_sort <=>
def <=>(object)
if (self == 100 or object == 100)
return -1
else
return self.old_sort object
end
end
end
puts (101 <=> 100)
Edit 1: Above is a fully working example.
Edit 2: As stated by johannes in the comments, you really shouldn't implement this exact code. This is merely a simple example of how to override your sorting method to do domain-specific logic. Also, updated the code to reflect johannes' other comment about comparing with both object and self.