ruby 2.0 how to access element in matrix by coordinate? - ruby

I'm new to ruby, but here is the problem. Say I have a matrix, and I need to modify a element at 1,2
mm = Matrix.build(2,4) {0}
mm[1][2] = 404
but this will rise error message
ArgumentError: wrong number of arguments (1 for 2)
from /Users/xxxxxx/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/matrix.rb:314:in `[]'
from (irb):11
from /Users/xxxxxx/.rvm/rubies/ruby-2.0.0-p0/bin/irb:16:in `<main>'
I have checked ruby doc, but didn't find any answer, sorry to ask such a stupid question...

Get element:
mm[1,2] #output 0
Set element:
No method can do that. Matrix is immutable object and cannot be changed (which is, IMHO, not so optimal). You can either copy the matrix by each to an array, change the element, and convert back, or use monkey patch
class Matrix
def []=(i, j, x)
#rows[i][j] = x
end
end
mm[1,2] = 404
Or if you don't want to monkey patch or want to be a bit hacky (although does not look good):
mm.send(:[]=, 1, 2, 404)

Related

Ruby error: undefined method `shift'

Brand new to Ruby. There are a couple of array methods I can't access.
EDIT:
I originally had:
puts 'give me a number to find phi of: '
K = gets
List = Array.new(K) #{|i| i}
List.drop(2)
List puts
Rec'd the error: in `initialize': no implicit conversion of String into Integer
so I changed line 3 above to:
List = Array.new(K.to_i) #{|i| i}
and am now receiving: undefined method `List' for main:Object
I'm trying to create an array based on user input, then drop or shift the first 2 elements of the array (the 0 and 1)
=================================
original post was unclear:
puts 'give me a number to find phi of: '
K = gets
puts K.shift
I'm sure it's something easy but can't figure it out. Am I missing a basic library or something? Any help would be appreciated!
This is the shortest way to find all primes between 2 and K in Ruby, you don't have to invent your own algo for finding primes when there's one already(http://ruby-doc.org/stdlib-1.9.3/libdoc/prime/rdoc/Prime.html)
require 'prime'
def find_primes_between_2_and(a_number)
Prime.each(a_number).map do |prime|
prime
end
end
puts 'Give me a number up to which to find primes:'
number = gets.to_i
puts find_primes_between_2_and(number)
I'm running thru Chris Pike's Ruby "Learning to Program" & am doing it as an exercise. But hey, thanks for the help.
My problem on the shift was passing it w/o a parameter. It should have been List.shift(2)
Thanks much!

Understanding strange output in multidimensional array

I am new to ruby and I was trying to iterate over a 2d array. I made a mistake in my code. From that mistake, I noticed some unexpected output.
s = [["ham", "swiss"], ["turkey", "cheddar"], ["roast beef", "gruyere"]]
i = 0;
s.each{
|array| so = array[i] # pin
puts so[i]
}
Due to #pin, if i = 0, output is h t r. i = 1 gives w h r. i > 1 gives an error:
C:/Ruby.rb in `block in <main>': undefined method `[]' for nil:NilClass (NoMethodError)
from C:/Ruby.rb:3:in `each'
from C:/Ruby.rb:3:in `<main>'
If I use |array| so = array # pin, then my code does not produce strange output. I'll just fix the remaining stuff to make my code iterate for all values that 'i' can have.
Please explain this.
PS: Working code is here
s = [["ham", "swiss"], ["turkey", "cheddar"], ["roast beef", "gruyere"]]
s.each{
|array| so = array
array.each{
|str| puts str
}
}
For each type of sandwich, when i is 0, so is the 1st element, which is the meat. so[0] is the first letter of the meat.
When i is 1, which is the 2nd element, which is the cheese. so[1] is the second letter of the cheese.
When i is 3, there is no third component to the sandwich. so so is nil. so[2] is asking for the nil[2].
nil is a class, like everything in ruby. But nil does not implement the [] method, as arrays and other classes that implement the Enumerable module do.
Since nil does not support the [] method, then you get the undefined method error.
Even operations that are built into other languages, like +, [], and == are methods that can be overridden in Ruby.
To understand exactly what's happening, try this bit of code:
class NilClass
def [] (i)
nil
end
end
Executing that will open up the existing NilClass, and add a method called []. Then you can do nil[1] and it will return nil. Changing an existing class like this is known as monkey patching in the Ruby world.
When you ask for so[2] you are actually asking for the third element, and if it doesn't exist, you'll get an error.
I recommend structuring your blocks like so:
s.each do |pair|
puts pair
end
Note the do/end instead of {} and the placement of the iteration variable inline with the each. Also note that this is equivalent to your "working code" so you don't need the extra iterator in this case.

Ruby find in array with offset

I'm looking for a way to do the following in Ruby in a cleaner way:
class Array
def find_index_with_offset(offset, &block)
[offset..-1].find &block
end
end
offset = array.find_index {|element| element.meets_some_criterion?}
the_object_I_want =
array.find_index_with_offset(offset+1) {|element| element.meets_another_criterion?}
So I'm searching a Ruby array for the index of some object and then I do a follow-up search to find the first object that matches some other criterion and has a higher index in the array. Is there a better way to do this?
What do I mean by cleaner: something that doesn't involve explicitly slicing the array. When you do this a couple of times, calculating the slicing indices gets messy fast. I'd like to keep operating on the original array. It's easier to understand and less error-prone.
NB. In my actual code I haven't monkey-patched Array, but I want to draw attention to the fact that I expect I'm duplicating existing functionality of Array/Enumerable
Edits
Fixed location of offset + 1 as per Mladen Jablanović's comment; rewrite error
Added explanation of 'cleaner' as per Mladen Jablanović's comment
Cleaner is here obviously subjective matter. If you aim for short, I don't think you could do better than that. If you want to be able to chain multiple such finds, or you are bothered by slicing, you can do something like this:
module Enumerable
def find_multi *procs
return nil if procs.empty?
find do |e|
if procs.first.call(e)
procs.shift
next true if procs.empty?
end
false
end
end
end
a = (1..10).to_a
p a.find_multi(lambda{|e| e % 5 == 0}, lambda{|e| e % 3 == 0}, lambda{|e| e % 4 == 0})
#=> 8
Edit: And if you're not concerned with the performance you could do something like:
array.drop_while{|element|
!element.meets_some_criterion?
}.drop(1).find{|element|
element.meets_another_criterion?
}

Ruby block method help

I was trying to see if I could reconstruct the Array class' delete_if iterator as my own method in order to see if I understood methods and blocks correctly. Here is what I coded:
def delete_if(arr)
for x in 0...arr.length
if (yield arr[x])
arr[x]=arr[x+1,arr.length]
redo
end
end
end
arr = [0,1,2,3,4,5]
delete_if(arr) {|value| value % 2 == 0}
This resulted in an error saying that the % method could not be identified in the last line. I know that value is going to be an integer so I am not sure why it would say this error. Can someone please explain? Also, in Ruby in general, how can you be sure that someone passes the correct type into a method? What if the method is supposed to take a string but they pass in an integer -- how do you prevent that??
Thanks!
def delete_if arr
for x in 0...arr.length
return if x >= arr.length
if yield arr[x]
arr[x..-1] = arr[(x + 1)..-1]
redo
end
end
end
Things I fixed:
it's necessary to mutate the array, if all you do is assign to the parameter, your changes will be local to the method. And for that matter, you were assigning your calculated array object to an element of the original array, which was the immediate cause of the error message.
since the array may become shorter, we need to bail out at the (new) end
of course you could just use arr.delete_at x but I couldn't correct the slice assignment without keeping the code pattern

What does 'yield called out of block' mean in Ruby?

I'm new to Ruby, and I'm trying the following:
mySet = numOfCuts.times.map{ rand(seqLength) }
but I get the 'yield called out of block' error. I'm not sure what his means. BTW, this question is part of a more general question I asked here.
The problem is that the times method expects to get a block that it will yield control to. However you haven't passed a block to it. There are two ways to solve this. The first is to not use times:
mySet = (1..numOfCuts).map{ rand(seqLength) }
or else pass a block to it:
mySet = []
numOfCuts.times {mySet.push( rand(seqLength) )}
if "numOfCuts" is an integer,
5.times.foo
is invalid
"times" expects a block.
5.times{ code here }
You're combining functions that don't seem to make sense -- if numOfCuts is an integer, then just using times and a block will run the block that many times (though it only returns the original integer:
irb(main):089:0> 2.times {|x| puts x}
0
1
2
map is a function that works on ranges and arrays and returns an array:
irb(main):092:0> (1..3).map { |x| puts x; x+1 }
1
2
3
[2, 3, 4]
I'm not sure what you're trying to achieve with the code - what are you trying to do? (as opposed to asking specifically about what appears to be invalid syntax)
Bingo, I just found out what this is. Its a JRuby bug.
Under MRI
>> 3.times.map
=> [0, 1, 2]
>>
Under JRuby
irb(main):001:0> 3.times.map
LocalJumpError: yield called out of block
from (irb):2:in `times'
from (irb):2:in `signal_status'
irb(main):002:0>
Now, I don't know if MRI (the standard Ruby implementation) is doing the right thing here. It probably should complain that this does not make sense, but when n.times is called in MRI it returns an Enumerator, whereas Jruby complains that it needs a block.
Integer.times expects a block. The error message means the yield statement inside the times method can not be called because you did not give it a block.
As for your code, I think what you are looking for is a range:
(1..5).map{ do something }
Here is thy rubydoc for the Integer.times and Range.

Resources