I would like to make a function so each time it is called it return a value that is incremented by 1 starting from 1.
I guess it could be made with a global variable, but not a pretty solution.
I'd probably do it this way:
class EverreadyBunnyCounter
def initialize
#counter = 0
end
def current
#counter
end
def next
#counter += 1
end
end
foo = EverreadyBunnyCounter.new
bar = EverreadyBunnyCounter.new
foo.next # => 1
bar.next # => 1
foo.next # => 2
bar.current # => 1
The current method isn't necessary but it's sometimes convenient to be able to peek at the current value without forcing it to increment.
Alternately, this might do it:
MAX_INT = (2**(0.size * 8 -2) -1)
counter = (1..MAX_INT).to_enum # => #<Enumerator: 1..4611686018427387903:each>
foo = counter.dup
bar = counter.dup
foo.next # => 1
foo.next # => 2
bar.next # => 1
bar.next # => 2
foo.next # => 3
Defining MAX_INT this way comes from "Ruby max integer". The downside is that you'll eventually run out of values because of the range being used to create the Enumerator, where the previous version using the EverreadyBunnyCounter class will keep on going.
Changing MAX_INT to Float::INFINITY would be a way to fix that:
counter = (1..Float::INFINITY).to_enum # => #<Enumerator: 1..Infinity:each>
foo = counter.dup
bar = counter.dup
foo.next # => 1
foo.next # => 2
bar.next # => 1
bar.next # => 2
foo.next # => 3
The Enumerator documentation has more information.
Something like this?
def incr
#n ||= 0
#n += 1
end
incr
#=> 1
incr
#=> 2
Related
I have been making a chess game and I need some help with hashes. Specifically how do I automatically name a hash table symbol using an iterator 'i'
8.times do |i = 0, x = 0|
i += 1
x += 1
pawnHash[:P] = "P#{i}",Pawn.new(x,2,"P#{i}","black")
end
puts pawnHash
the symbol should look like this:
:P1. But is seems impossible to name a hash using the variable 'i'
The full set of 8 symbols should look like this: :P1, :P2, :P3 ... etc.
I tried doing :P + i when declaring the key/value pair, but I got a syntax error due to the '+' sign.
Are you trying to make the key a symbol?
You can do hash["P#{i}".to_sym]
2.0.0-p247 :016 > i = 2
=> 2
2.0.0-p247 :017 > h = {}
=> {}
2.0.0-p247 :018 > h["P#{i}".to_sym] = "value"
=> "value"
2.0.0-p247 :019 > h
=> {:P2=>"value"}
2.0.0-p247 :020 > h.keys.first.class
=> Symbol
Or you can do :"P#{i}"
You can simplify your loop and make it more Ruby-like:
pawn_hash = {}
8.times { |i| pawn_hash["P#{ i + 1 }".to_sym] = "P#{ i + 1}" }
pawn_hash
# => {:P1=>"P1",
# [...]
# :P8=>"P8"}
You could avoid using i + 1 by assigning it to an intermediate variable if you want to play the DRY game:
pawn_hash = {}
8.times do |i|
c = i + 1
pawn_hash["P#{ c }".to_sym] = "P#{ c }"
end
pawn_hash
# => {:P1=>"P1",
# [...]
# :P8=>"P8"}
Or, use a different loop:
pawn_hash = {}
1.upto(8) { |i| pawn_hash["P#{ i }".to_sym] = "P#{ i }" }
pawn_hash
# => {:P1=>"P1",
# [...]
# :P8=>"P8"}
In Ruby we use snake_case, instead of camelCase, for variable and method names. Classes and Modules get camelCase.
Also, meditate on these:
pawn_hash = 8.times.map { |i| ["P#{ i + 1 }".to_sym, "P#{ i + 1}"] }.to_h
# => {:P1=>"P1",
# :P2=>"P2",
# :P3=>"P3",
# :P4=>"P4",
# :P5=>"P5",
# :P6=>"P6",
# :P7=>"P7",
# :P8=>"P8"}
pawn_hash = Hash[8.times.map { |i| ["P#{ i + 1 }".to_sym, "P#{ i + 1}"] }]
# => {:P1=>"P1",
# :P2=>"P2",
# :P3=>"P3",
# :P4=>"P4",
# :P5=>"P5",
# :P6=>"P6",
# :P7=>"P7",
# :P8=>"P8"}
# :P8=>"P8"}
It's not necessary to loop and assign to the hash. Instead, it's very Ruby-like to do it all in one pass. The times method is an iterator. map can iterate over that and will return the block values for each iteration. to_h is a more modern way in Ruby to convert an array to a hash, just as is using Hash[...].
In PHP, I can do this:
$a = 1;
$c = 'a';
$$c = 2;
//now $a == 2
Is there any equivalent in ruby? By which I mean, any simple way to have it dereference a variable during execution like this? I'd rather not use eval, because it looks messy - I've already determined that eval can't be called as a method of a string.
It is possible but it's a bit more complicated., and you actually have two possibilities:
Kernel#local_variables
Returns the names of the current local variables.
fred = 1
for i in 1..10
# ...
end
local_variables #=> [:fred, :i]
Binding#local_variable_get/set
Returns a value of local variable symbol.
def foo
a = 1
binding.local_variable_get(:a) #=> 1
binding.local_variable_get(:b) #=> NameError
end
This method is short version of the following code.
binding.eval("#{symbol}")
if you just need this you can do
a = 1
c = 'a'
eval("#{c} = 2")
a == 2 # => true
... but this is moron way to do this
if you need this for instance variables
class Foo
attr_reader :a
def initialize
#a = 1
end
end
foo = Foo.new
foo.instance_variable_get(:a) #=> 1
foo.a #=> 1
foo.instance_variable_set(:"#a", 2)
foo.a #=> 2
...you can also eval instance like this:
# ...
foo.instance_eval do
#a = 'b'
end
foo.a # => 'b'
Im currently going through a book and there is a pice of code that I don't quite understand:
class RevealingReferences
attr_reader :wheels
def initialize(data)
#wheels = wheelify(data)
puts data
end
def diameters
wheels.collect do |wheel|
puts "test"
wheel.rim + (wheel.tire*2)
end
end
Wheel = Struct.new(:rim, :tire)
def wheelify(data)
data.collect{|cell|
Wheel.new(cell[0], cell[1])}
end
end
end
puts RevealingReferences.new([3,2,5,8]).diameters
and I get the following output:
3
2
5
8
test
test
test
test
3
2
1
0
1) Now the 3,2,5,8 I understand, but why does not display in array format [3,2,5,8] rather its being displayed one int at a time.
2) Also, in the wheels.collect block, the output prints "test" twice before putting in the output, should it not be "test" value "test" value
3) Also, the answer 3,2,1,0 don't make any sense, when I set #wheels should wheels not be a collection of an array of 2 elements rather then 4?
1) Now the 3,2,5,8 I understand, but why does not display in array
format [3,2,5,8] rather its being displayed one int at a time.
This is due to how puts works. When it sees an array, it prints the #to_s of each element
puts [1,2,3]
# >> 1
# >> 2
# >> 3
If you want it to look like an array, you should inspect it before printing it
puts [1,2,3].inspect
# >> [1, 2, 3]
There's also a shorthand for this, the method p
p [1,2,3]
# >> [1, 2, 3]
2) Also, in the wheels.collect block, the output prints "test" twice
before putting in the output, should it not be "test" value "test"
value
The only thing printing the values is the puts statement on the return value of diameters, so they won't print until after they have been collected. If you wanted to print it after each test, you should probably do something like
def diameters
wheels.collect do |wheel|
puts "test"
p wheel.rim + (wheel.tire*2)
end
end
Which would print:
test
3
test
2
test
1
test
0
3) Also, the answer 3,2,1,0 don't make any sense, when I set #wheels
should wheels not be a collection of an array of 2 elements rather
then 4?
Based on what you're saying here, I assume your data is not in the format you intended. You're passing in [3,2,5,8], but this implies that you meant to pass in [[3,2],[5,8]], or to map across every pair of values:
def wheelify(data)
data.each_slice(2).collect do |cell|
Wheel.new(cell[0], cell[1])
end
end
The reason it isn't doing what you think is because without doing one of these, the cell variable is actually just a number. Since numbers have the brackets method defined on them, they wind up working in this case. But the brackets method just returns 1 or 0, depending on the bit (base 2) at that position:
five = 5
five.to_s(2) # => "101"
five[2] # => 1
five[1] # => 0
five[0] # => 1
So in the case of 3, wheel.rim + (wheel.tire*2) becomes
cell = 3
cell.to_s(2) # => "11"
rim = cell[0] # => 1
tire = cell[1] # => 1
rim + tire * 2 # => 3
And in the case of 2:
cell = 2
cell.to_s(2) # => "10"
rim = cell[0] # => 0
tire = cell[1] # => 1
rim + tire * 2 # => 2
And 5:
cell = 5
cell.to_s(2) # => "101"
rim = cell[0] # => 1
tire = cell[1] # => 0
rim + tire * 2 # => 1
And 8:
cell = 8
cell.to_s(2) # => "1000"
rim = cell[0] # => 0
tire = cell[1] # => 0
rim + tire * 2 # => 0
Which is why diameters returns [3, 2, 1, 0], explaining the last four digits you see.
1) puts will output each argument on a new line, or if the argument is an array, each element of an array on a new line
2) puts "test" is running in the wheels.collect block, there are four Wheel objects created so it outputs four tests while creating the diameters array.
3) The real problem is what seems like a typo either in your book or the transfer of the code to your test environment. I think that last line was meant to read
puts RevealingReferences.new([[3,2],[5,8]]).diameters
Otherwise, the Wheel.new line
Wheel.new(cell[0], cell[1])}
is calling FixNum#[] giving you the n-th bit of the integer. This was a bit of surprise to me too - it seems like a lot could go subtly wrong when accidentally supplying an integer instead of an Array.
With the original code, cell[0] and cell[1] evaluates as 3[0] and 3[1] for the first element of data. With the correction you have the array [3,2][0] => 3, and [3,2][1] => 2 which makes much more understandable code as a "collect" example.
1- collect is a iterator method that accepts a block of code.The collect iterator returns all the elements of a collection.
2- u haven't specified the value to be displayed. do "puts wheel.rim + (wheel.tire*2)".
3- if u print the 'wheel' in the collect block of diameters method, its
"#<struct RevealingReferences::Wheel rim=1, tire=1>"
"#<struct RevealingReferences::Wheel rim=0, tire=1>"
"#<struct RevealingReferences::Wheel rim=1, tire=0>"
"#<struct RevealingReferences::Wheel rim=0, tire=0>"
When the "wheel.rim + (wheel.tire*2)" statement is executed, the result is 3,2,1,0 and each result is returned. if the statement "puts wheel" is added in the collect block for diameter and the prog executed, u wont see the values (3,2,1,0) in the output.
If I have variables as below,
i = 1
k1 = 20
is there any ways to get values of k1 with the interpolation of i?
Something like,
k"#{i}"
=> 20
Thanks in advance.
It depends on whether it's a local variable or a method. send "k#{i}" should do the trick with methods:
class Foo
attr_accessor :i, :k1
def get
send "k#{i}"
end
end
foo = Foo.new
foo.i = 1
foo.k1 = "one"
foo.get
# => "one"
If you really need to, you can access local variables using the current Binding and local_variable_get:
i = 1
k1 = "one"
local_variables
# => [:i, :k1]
binding.local_variable_get("k#{i}")
# => "one"
This is pretty awful though. In this instance you'd be better off using a Hash:
i = 1
k = {1 => "one"}
k[i]
# => "one"
>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5
how can I set 'b' to actually be 'a' so that in the example, the variable a will become four as well. thanks.
class Ref
def initialize val
#val = val
end
attr_accessor :val
def to_s
#val.to_s
end
end
a = Ref.new(4)
b = a
puts a #=> 4
puts b #=> 4
a.val = 5
puts a #=> 5
puts b #=> 5
When you do b = a, b points to the same object as a (they have the same object_id).
When you do a = some_other_thing, a will point to another object, while b remains unchanged.
For Fixnum, nil, true and false, you cannot change the value without changing the object_id. However, you can change other objects (strings, arrays, hashes, etc.) without changing object_id, since you don't use the assignment (=).
Example with strings:
a = 'abcd'
b = a
puts a #=> abcd
puts b #=> abcd
a.upcase! # changing a
puts a #=> ABCD
puts b #=> ABCD
a = a.downcase # assigning a
puts a #=> abcd
puts b #=> ABCD
Example with arrays:
a = [1]
b = a
p a #=> [1]
p b #=> [1]
a << 2 # changing a
p a #=> [1, 2]
p b #=> [1, 2]
a += [3] # assigning a
p a #=> [1, 2, 3]
p b #=> [1, 2]
You can't. Variables hold references to values, not references to other variables.
Here's what your example code is doing:
a = 5 # Assign the value 5 to the variable named "a".
b = a # Assign the value in the variable "a" (5) to the variable "b".
b = 4 # Assign the value 4 to the variable named "b".
a # Retrieve the value stored in the variable named "a" (5).
See this article for a more in-depth discussion of the topic: pass by reference or pass by value.
As has been noted the syntax you are using can not be done. Just throwing this out there though you could make a wrapper class it depends what you actually want to do
ruby-1.8.7-p334 :007 > class Wrapper
ruby-1.8.7-p334 :008?> attr_accessor :number
ruby-1.8.7-p334 :009?> def initialize(number)
ruby-1.8.7-p334 :010?> #number = number
ruby-1.8.7-p334 :011?> end
ruby-1.8.7-p334 :012?> end
=> nil
ruby-1.8.7-p334 :013 > a = Wrapper.new(4)
=> #<Wrapper:0x100336db8 #number=4>
ruby-1.8.7-p334 :014 > b = a
=> #<Wrapper:0x100336db8 #number=4>
ruby-1.8.7-p334 :015 > a.number = 6
=> 6
ruby-1.8.7-p334 :016 > a
=> #<Wrapper:0x100336db8 #number=6>
ruby-1.8.7-p334 :017 > b
=> #<Wrapper:0x100336db8 #number=6>
You can use arrays:
a = [5]
b = a
b[0] = 4
puts a[0] #=> 4
This idea is based on this answer.
Just for the sake of reference.
>> a = 5
=> 5
>> a.object_id
=> 11
>> b = a
=> 5
>> b.object_id
=> 11
>> b = 4
=> 4
>> b.object_id
=> 9
>> a.object_id
=> 11
# We did change the Fixnum b Object.
>> Fixnum.superclass
=> Integer
>> Integer.superclass
=> Numeric
>> Numeric.superclass
=> Object
>> Object.superclass
=> BasicObject
>> BasicObject.superclass
=> nil
I hope this gives us all a little better understanding about objects in Ruby.
One option in cases where you feel you would like to have direct pointer operations is to use the replace method of Hashes, Arrays & Strings.
this is useful for when you would like to have a method return a variable that a proc the method sets up will change at a later date, and don't want the annoyance of using a wrapper object.
example:
def hash_that_will_change_later
params = {}
some_resource.on_change do
params.replace {i: 'got changed'}
end
params
end
a = hash_that_will_change_later
=> {}
some_resource.trigger_change!
a
{i: 'got changed'}
It's probably better generally to use explicit object wrappers for such cases, but this pattern is useful for building specs/tests of asynchronous stuff.
I'm no Ruby expert. But for a technically crazy kluge...that would only work if you felt like going through eval every time you worked with a variable:
>> a = 5
=> 5
>> b = :a
=> :a
>> eval "#{b} = 4"
=> 4
>> eval "#{a}"
=> 4
>> eval "#{b}"
=> 4
Note that a direct usage of b will still give you :a and you can't use it in expressions that aren't in eval:
>> b
=> :a
>> b + 1
NoMethodError: undefined method `+' for :a:Symbol
...and there are certainly a ton of caveats. Such as that you'd have to capture the binding and pass it around in more complex scenarios...
'pass parameter by reference' in Ruby?
#Paul.s has an answer for if you can change the point of declaration to be a wrapper object, but if you can only control the point of reference then here's a BasicReference class I tried:
class BasicReference
def initialize(r,b)
#r = r
#b = b
#val = eval "#{#r}", #b
end
def val=(rhs)
#val = eval "#{#r} = #{rhs}", #b
end
def val
#val
end
end
a = 5
puts "Before basic reference"
puts " the value of a is #{a}"
b = BasicReference.new(:a, binding)
b.val = 4
puts "After b.val = 4"
puts " the value of a is #{a}"
puts " the value of b.val is #{b.val}"
This outputs:
Before basic reference
the value of a is 5
After b.val = 4
the value of a is 4
the value of b.val is 4