What does the bracket operator do to a FixNum in Ruby? - ruby

Coming from Python I find the following behaviour very surprising:
irb(main):211:0> x= 33
=> 33
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0
Is there a rationale/philosophy for not raising an error in this example?

The bracket operator gives you the nth bit of the binary representation:
http://ruby-doc.org/core-2.1.2/Fixnum.html#method-i-5B-5D

You might be a little confused about what this is doing internally, but that's normal when dealing with Ruby because it's quite unlike other scripting languages. Unless you've used SmallTalk it might even seem insane.
When Ruby sees the following code:
x = 6
x[1]
What it's actually doing is this:
x.send(:[], 6) # Send :[] method call to x with arguments [ 6 ]
The x object is free to interpret that however it wants, and the behaviour is typically (though not always) defined by the class x belongs to if x is a normal instance.
In this case it's returning the bit at a given index, equivalent to x & (1 << 6) >> 6.
Sometimes the [] method does several things:
string = "brackets"
# Retrieve a single character
string[1]
# => "r"
# Retrieve a substring
string[5,2]
# => "et"
# Perform a pattern match
string[/[^aeiou]+/]
# => "br"
This also does some pretty crazy things since you can apply it to a Proc as well:
fn = lambda { |x| x + 1 }
# Conventional (explicit) call
fn.call(2)
# => 3
# Square bracket method
fn[5]
# => 6
Since Ruby leans very heavily on Duck Typing, this means that you can write a Proc to fill in where you'd normally have a Hash or an Array and the method receiving your object is none the wiser.
It's this flexibility in leaving the meaning of x[...] for your own class instance x up to you that makes it pretty powerful.
For example:
class Bracketeer
def [](i)
"%d brackets" % i
end
end
bracketeer = Bracketeer.new
bracketeer[6]
# => "6 brackets"
This simple notation often comes in handy when you're trying to create a minimal interface for a class of yours. In many cases you can use something simple like [] to replace what would be a more verbose method like find_by_id or cache_fetch.

Certainly. You'll find that the manual is quite illuminating.
This is returning the binary bit for the bit position value as a zero or one.

It is returning the n'th bit as rightfully observed by #msergeant.
What this means is, for the number 33, its binary representation is:
Index : [7][6][5][4] [3][2][1][0]
Bits : 0 0 1 0 0 0 0 1
Which explains the output:
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

Related

Optimize print output where i use check on zero. Ruby

Currently, I'm having print like this
print ((stamp_amount[0], 'first mark') unless stamp_amount[0].zero?), (', ' if !stamp_amount[0].zero? && !stamp_amount[1].zero?),
((stamp_amount[1], 'second mark') unless stamp_amount[1].zero?)
stamp_amount is an array with 2 integer values
Let's say in the current situation stamp_amount[0] = 10 and stamp_amount[1] = 3
Output preview:
10 first mark, 3 second mark
So if stamp_amount[0] = 0 the 10 first mark, part won't be show. Same if stamp_amount[1] = 0 the , 3 second mark part won't be shown
For me, it seems a little bit incorrect in terms of theory. Could you please suggest me the more correct or less painful print of this? :)
Cheers!
Your code is trying to join a sequence of up to two elements with a separator. The joining is a solved problem, see Array#join.
The problem can be then reduced to "how can I produce the correct sequence, given my stamp_amount input". Now this can be done in a thousand ways. Here's one:
def my_print(stamp_amount)
ary = [
!stamp_amount[0].zero? && stamp_amount[0],
!stamp_amount[1].zero? && stamp_amount[1],
].select{|elem| elem }
ary.join(', ')
end
my_print([10, 3]) # => "10, 3"
my_print([0, 3]) # => "3"
my_print([10, 0]) # => "10"
my_print([0, 0]) # => ""
Here's another
ary = []
ary << stamp_amount[0] unless stamp_amount[0].zero?
ary << stamp_amount[1] unless stamp_amount[1].zero?
ary.join(', ')
Here's yet another. This version can handle stamp_amount of any length.
ary = stamp_amount.reject(&:zero?)
ary.join(', ')
I'd go with the third, but the second one may be the easiest to understand for a beginner.
Use the select, as an alternative to reject (shown in part 3 of the answer by Sergio Tulentsev). It is just asa readable, and depending on the context and on the future changes to the code, you may prefer one versus the other.
puts stamp_amount.select{ |a| !a.zero? }.join(", ")
A few examples of inputs and outputs are:
stamp_amount output
--------------------------------------------------------------------------
10, 3 10, 3
10, 0 10
0, 3 3
0, 0 (prints an empty line, because the selected array is empty)
You're calculating zero? on index points more often than is needed, but the first thing I would look at refactoring here is the readability of the code. It might be nicer to calculate the message to print outside of the print method and explain what is happening with variable names.
# rubocop is going to complain about variable assignment like this
first_amount, second_amount = *stamp_amount
We can actually use the reason rubocop prefers the .zero? over == 0 or .empty? method to guide our development. zero? is in essence just empty? but it communicates the meaning of what you are attempting to do in a better manner. I would use this reasoning when assigning strings to variables that explain what they are doing.
some_name_that_explains_what_this_is_0 = "#{first_amount} piecu centu marka"
some_name_that_explains_what_this_is_1 = "#{second_amount} tris centu marka"
Your current code is confusing as you have the possibility of printing a string like "10 tris centu marka" which does not make lexical sense and probably not what you are after considering tis evaluates to 'second mark', which would pose an issue if the first value is zero. We also could reject zero integers before we start converting them to strings.
array = [1, 0].reject(&:zero?)
Now we can take the array and do something like:
string = []
array.each_with_index { |e, i| string << "#{e} #{Ordinalize.new(i).ordinalize} mark" }
message = string.join(', ')
print(message)
# ord class
class Ordinalize
def initialize(value)
#value = value
end
def ordinalize
mapping[#value]
end
def mapping
# acounting for zero index
['first', 'second']
end
end
where we are calculating the ordinalization and letting our new class handle the sentence structure for us.
Outputs:
[1, 0] => "1 first mark"
[0, 1] => "1 first mark"
[1, 2] => "1 first mark, 2 second mark"

Ruby—integer substring (subbit?)

Substrings work where "hello"[0..2] returns "hel"
Is there an integer equivalent, that returns the sub-bits, as in 9[1..3] returns 4 or "100"?
Context:
I'm trying to do a genetic algorithm, and there is a cross over stage where you split two chromosomes in two, then swap halves, e.g. "10101010" crossed with "00000000" at i = 4 would be "00001010", "10100000"
However, I'm doing this a few million times, so using strings is inefficient, so is there a bitwise way to do this?
You might consider refining the class Fixnum to permit Fixnum#[]'s argument to be either a bit index or a range of bit indices.
module StabBitRange
def [](arg)
case arg
when Range
mask = arg.reduce(0) { |n, idx| n |= (1 << idx) }
(self & mask) >> arg.first
else
super
end
end
end
module StabBits
refine Fixnum do
prepend StabBitRange
end
end
See Refinements and Module#prepend. Prepend StabBitRange moves the methods contained therein (here just one) before the methods with the same names in Fixnum in the ancestor chain. The alternative (commonly used before Prepend was introduced in Ruby v2.0) is to alias Fixnum#[] and then redefine Fixnum[] to be the new method that takes either a bit index or a range of bit indices. (See the edit history of this answer to see how that is done.) I expect readers will agree that Prepend is a more sensible way of doing that.
To make this code available for use we need only invoke the keyword using.
using StabBits
n = 682
n.to_s(2) #=> "1010101010"
n[0] #=> 0
n[1] #=> 1
n[2] #=> 0
n[0..7] #=> 170 170.to_s(2) => "10101010"
n[1..7] #=> 85 85.to_s(2) => "1010101"
n[2..6] #=> 10 10.to_s(2) => "1010"
When StabBitRange#\[\] is called and the argument is not a range, super invokes Fixnum#[] and passes the argument. That method handles argument errors as well as returning the desired bit when there are no errors.
When this code is run in IRB, the following exception is raised: RuntimeError: main.using is permitted only at top level. That's because IRB is running at the top level, but code run within IRB is running at a higher level from the perspective of the Ruby parser. To run this in IRB it is necessary to enclose using StabBits and the code following in a module.

How do I destructure a range in Ruby?

Is it possible to use destructuring in ruby to extract the end and beginning from a range?
module PriceHelper
def price_range_human( range )
"$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
end
end
I know that I can use array coercion as a really bad hack:
first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)
But is there a syntactical way to get begin and end without actually manually creating an array?
min, max = (1..10)
Would have been awesome.
You can use minmax to destructure ranges:
min, max = (1..10).minmax
min # => 1
max # => 10
If you are using Ruby before 2.7, avoid using this on large ranges.
The beginning and end? I'd use:
foo = 1..2
foo.min # => 1
foo.max # => 2
Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.
end is not the same as max: in 1...10, end is 10, but max is 9
That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):
start_value = 1
end_value = 2
foo = start_value...end_value
foo.end # => 2
foo.max # => 1
foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1
max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.
In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.
... is more confusing and leads to increased maintenance problems so its use is not recommended.
No, Until I am proven incorrect by Cary Swoveland, Weekly World News or another tabloid, I'll continue believing without any evidence that the answer is "no"; but it's easy enough to make.
module RangeWithBounds
refine Range do
def bounds
[self.begin, self.end]
end
end
end
module Test
using RangeWithBounds
r = (1..10)
b, e = *r.bounds
puts "#{b}..#{e}"
end
Then again, I'd just write "#{r.begin.number_to_currency}..#{r.end.number_to_currency}" in the first place.
Amadan's answer is fine. you just need to remove the splat (*) when using it since it is not needed
eg,
> "%s to %s" % (1..3).bounds.map{|x| number_to_currency(x)}
=> "$1.00 to $3.00"

Simple sort in Ruby without using sort method (note that the list to be sorted is "strings")

Given
30.02 -88.87 10.58 -99.22 107.33
to sort without the sort method. I have spent a few hours on this without any success.
def simple_sort(list) # I have to start with this method
list = list.split(' ') # I understand i need to .split to get arrays
Because they're floats I need a way to make them floats with to_f method .each(&:to_f) I saw this before but I'm not sure I understand the ":". I thought colon made objects symbols so anyone please explain (&:to_f) to me?
sorted_list = [] #thought of creating an empty array to store the new list
This is the part that gets tricky! Where do I go from here?
I want to go through each item in the array, find the smallest number and add it to the sorted_list
def sort_list(list)
list = list.split(' ').map(&:to_f)
sort = []
while sort.length < list.length
sort << list.min
list.delete(list.min)
end
sort = sort.join(' ')
return sort
end
instead of using the <=>, what would make this code work?
Open IRB and try things:
>> foo = '30.02 -88.87 10.58 -99.22 107.33'
"30.02 -88.87 10.58 -99.22 107.33"
>> foo.split
[
[0] "30.02",
[1] "-88.87",
[2] "10.58",
[3] "-99.22",
[4] "107.33"
]
So split breaks the string on whitespace, so far so good.
>> foo.split.each(&:to_f)
[
[0] "30.02",
[1] "-88.87",
[2] "10.58",
[3] "-99.22",
[4] "107.33"
]
Hmm... the values didn't change so each might not be doing what you think it does. Trying map instead:
>> foo.split.map(&:to_f)
[
[0] 30.02,
[1] -88.87,
[2] 10.58,
[3] -99.22,
[4] 107.33
]
Once the values are converted to floats then it becomes easy to sort them.
Note: You can use the <=> operator (AKA "spaceship") to tell you whether one is less-than, equal, or greater-than another, which makes it easy to know when you should swap them. For instance:
0 <=> 1 # => -1
1 <=> 1 # => 0
2 <=> 1 # => 1
You should read the documentation for the Comparable module, which makes it really easy to add additional functionally to a class by defining the <=>(other) method.
map allows us to modify/transform an array's elements, whereas each only iterates over them. You can use each to mess with the elements, but it's not generally what you want to do since map! makes it easier to transform things.
Regarding &:to_f. This was a hack on Ruby's symbols a while back, that was added to Rails. It turned out to be so useful that it was pulled into Ruby itself. It's called a "symbol to proc" and is discussed in "Ruby ampersand colon shortcut".

Can you use semicolons in Ruby?

When learning Ruby, I noticed that in all the examples there are no semicolons. I am aware that this is perfectly fine as long as each statement is on its own line. But what I am wondering is, can you use semicolons in Ruby?
Yes.
Ruby doesn't require us to use any character to separate commands, unless we want to chain multiple statements together on a single line. In this case, a semicolon (;) is used as the separator.
Source: http://articles.sitepoint.com/article/learn-ruby-on-rails/2
As a side note, it's useful to use semi-colons in your (j)irb session to avoid printing out a ridiculously long expression value, e.g.
irb[0]> x = (1..1000000000).to_a
[printout out the whole array]
vs
irb[0]> x = (1..100000000).to_a; nil
Nice especially for your MyBigORMObject.find_all calls.
Semicolon: yes.
irb(main):018:0> x = 1; c = 0
=> 0
irb(main):019:0> x
=> 1
irb(main):020:0> c
=> 0
You can even run multiple commands separated by semicolons in a one-liner loop
irb(main):021:0> (c += x; x += 1) while x < 10
=> nil
irb(main):022:0> x
=> 10
irb(main):023:0> c
=> 45
The only situation I've come across that semicolons are useful is when declaring alias methods for attr_reader.
Consider the following code:
attr_reader :property1_enabled
attr_reader :property2_enabled
attr_reader :property3_enabled
alias_method :property1_enabled?, :property1_enabled
alias_method :property2_enabled?, :property2_enabled
alias_method :property3_enabled?, :property3_enabled
By using semicolons we can reduce this down 3 lines:
attr_reader :property1_enabled; alias_method :property1_enabled?, :property1_enabled
attr_reader :property2_enabled; alias_method :property2_enabled?, :property2_enabled
attr_reader :property3_enabled; alias_method :property3_enabled?, :property3_enabled
To me this doesn't really take away from readability.
Yes, semicolons can be used as statement separators in Ruby.
Though my typical style (and most code I see) puts a line of code on each line, so the use of ; is pretty unnecessary.
It can be interesting to use semicolons to preserve the block syntax as in this example:
a = [2, 3 , 1, 2, 3].reduce(Hash.new(0)) { |h, num| h[num] += 1; h }
You maintain one line of code.
Splitting lines with semicolons is something very important sometimes.
Say you want to calculate something trivial like depositing your money and want to calculate inflation. And let's say you don't want to do it in irb (because it's terribly buggy), you can use your shell, and a semicolon is needed:
$ ruby -e "x = 7_200 ; 10.times { x += (x * 6.6 / 100.0) } ; puts x"
13642.832381464528
Same thing applies if you want to quickly parse JSON or so just from the command shell or want to do something really quick.
There's a clear advantage of having blocks over languages that uses indentation instead of blocks. And semicolons are helpful to join multiple lines.
In most cases using a semicolon is a bad idea in Ruby. But in some cases it's mandatory. For example, consider this valid ruby code:
def x(*)
5
end
p x 1, '', [1,2,3], {1 => '1'} # => 5
Above code works completely fine.
In ruby, you can use arg instead of (arg). In case of * though, you need a semicolon if you plan to omit the parentheses.
So this won't work:
def x *
5
end
p x 1, '', [1,2,3], {5 => '5'}
But this will:
def x *;
5
end
p x 1, '', [1,2,3], {5 => '5'}
You can also use def x*;. But the parser can't parse your code if you miss the semicolon (tried ruby 1.9 to 3.1).
So there are some cases like these where semicolons are needed much like JavaScript. And such code aren't probably clean code.

Resources