Troubles: Matrices, Vectors and Arrays - ruby

As far as I understood, matrices are very inflexible to work with. Therefor, I'm trying to get an array of vectors do deal with. My needs are: to be able to add vectors and make arithmetical operations on their components. Writing the code below,
require 'matrix'
x = Matrix.rows( IO.readlines("input.txt").each {|line| line.split} )
puts x.row_vectors
ruby falls into an exception. Why?
matrix.rb:1265:in `to_s': undefined method `join' for "1.2357 2.1742 -5.4834 -2.0735":String (NoMethodError)
OK then, I've calmed down and tried another approach. I wrote:
a = Array.[]( IO.readlines("input.txt").each {|line| Vector.[](line.split) } )
But the only way I can access my vectors inside an array is adressing the second index:
puts a[0][0]
This means, that when I would like to access desired scalar inside a vector, I'll will be forced to use the third index, like:
puts a[0][0][1]
So, the second question is - where the hell that second index comes from? How to get rid of it? Am I missing something when reading data into array?

I can't reproduce your first problem. Extracting what looks like input.txt, I can execute that first expression without an exception.
As to the second question, your expression seems kind of complex. How about:
b = IO.readlines("input.txt").map { |x| x.split(' ') }
This will get you a "2D" array of arrays, and you will need only two subscripts. (As to your question about where did the extra array come from, you got one from the Array constructor, one from IO.readlines, and one from the Vector constructor . . . I think.)
Or maybe:
result = []
IO.foreach('input.txt') { |ln| result << ln.split(' ') }

Related

when and how to convert section of code to a method in ruby

I had a question regarding identifying all the points next to a given cell or set of cells) in a matrix (see Need a Ruby way to determine the elements of a matrix "touching" another element). Since no suitable ideas were put forth, I decided to proceed via brute force.
The code below successfully does what I sought to do. The array tmpl (template) contains a map of how to get from a given coordinate (provided by atlantis) to the 8 cells surrounding it. I then construct an array sl (shoreline) that contains all the “underwater” land touching the shoreline of atlantis by summing each element of atlantis with all elements of tmpl.
# create method to determine elements contiguous to atlantis
require 'matrix'
atlantis = [[2,3],[3,4]]
tmpl = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
ln = 0
sl = []
while ln < atlantis.length
n = 0
tsl = []
while n < 8
tsl[n] = [atlantis[ln], tmpl[n]].transpose.map { |x| x.reduce(:+) }
n = n+ 1
end
sl = sl + tsl
ln = ln + 1
end
sl = sl - atlantis
sl.uniq!
sl.to_a.each { |r| puts r.inspect }
But I have a problem (one of many remaining) in that I still need 2 levels of loops above what’s shown here (one to keep adding land to atlantis until it reaches a set size and another to make additional islands, Bermuda, Catalina, etc.) and already this is becoming difficult to read and follow. My vague understanding of object oriented programming suggests that this cold be improved by turning some of these loops into methods. However, I learned to program 35 years ago in basic and am struggling to learn Ruby as it is. So my requests are:
Is in fact better to turn these into methods?
If so, would anyone be willing to show me how that’s done by changing something into an method?
What do you do when you add additional levels and discover you need to change something in a lower method as a result? (e.g, after figuring out the simple case of how to create sl with just one value in atlantis, I had to go back and rework it for longer values.)
I hoping by asking the question in this way, it becomes something also useful to other nubies.
BTW, this bit .transpose.map { |x| x.reduce(:+) } I found on Stack Overflow (after hours of trying to do it ‘cause it should be simple and if I couldn’t do it I must be missing something obvious. Yeah, I bet you know too.) lets you add two arrays element by element and I have no idea how it works.)
already this is becoming difficult to read and follow
One way of making it less difficult to read and follow is to try to make the code "self document", by using readable variable names and Ruby idioms to reduce the clutter.
A quick refactor of your code gives this:
require 'matrix'
atlantis = [[2,3],[3,4]]
template = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
shoreline = []
atlantis.each do |atlantum|
shoreline += template.inject([]) do |memo, element|
memo << [atlantum, element].transpose.map { |x| x.reduce(:+) }
memo
end
end
shoreline = shoreline - atlantis
shoreline.uniq!
shoreline.each { |r| puts r.inspect }
The main processing block is half the size, and (hopefully) more readable, and from here you can use the extract method refactor to tidy it further if you still need/want to.

Ruby: how to find the next match in an array

I have to search an item in an array and return the value of the next item. Example:
a = ['abc.df','-f','test.h']
i = a.find_index{|x| x=~/-f/}
puts a[i+1]
Is there any better way other than working with index?
A classical functional approach uses no indexes (xs.each_cons(2) -> pairwise combinations of xs):
xs = ['abc.df', '-f', 'test.h']
(xs.each_cons(2).detect { |x, y| x =~ /-f/ } || []).last
#=> "test.h"
Using Enumerable#map_detect simplifies it a litte bit more:
xs.each_cons(2).map_detect { |x, y| y if x =~ /-f/ }
#=> "test.h"
The reason something like array.find{something}.next doesn't exist is that it's an array rather than a linked list. Each item is just it's own value; it doesn't have a concept of "the item after me".
#tokland gives a good solution by iterating over the array with each pair of consecutive items, so that when the first item matches, you have your second item handy. There are strong arguments to be made for the functional style, to be sure. Your version is shorter, though, and I'd argue that yours is also more quickly and easily understood at a glance.
If the issue is that you're using it a lot and want something cleaner and more to the point, then of course you could just add it as a singleton method to a:
def a.find_after(&test)
self[find_index(&test).next]
end
Then
a.find_after{|x| x=~/-f/}
is a clear way to find the next item after the first match.
All of that said, I think #BenjaminCox makes the best point about what appears to be your actual goal. If you're parsing command line options, there are libraries that do that well.
I don't know of a cleaner way to do that specific operation. However, it sure looks like you're trying to parse command-line arguments. If so, I'd recommend using the built-in OptionParser module - it'll save a ton of time and hair-pulling trying to parse them yourself.
This article explains how it works.
Your solution working with indexes is fine, as others have commented. You could use Enumerable#drop_while to get an array from your match on and take the second element of that:
a = ['abc.df','-f','test.h']
f_arg = a.drop_while { |e| e !~ /-f/ }[1]

How to recurse through arrays in Ruby

I'm trying to use the two following methods to recursively traverse arrays of arrays until the bottom and then come back up with the match results.
You know how in a tennis tournament they start with 32 matches and pair by pair the winner moves ahead, and at the end there's only one winner? That's what I want to replicate in Ruby.
I created a match_winner that always returns the first array for the sake of simplicity. Then, I send the whole tournament array into winner that calls itself recursively until it finds a simple array corresponding to a single match.
def match_winner(array_of_arrays)
return array_of_arrays[0]
end
def winner(tournament)
if tournament[0][0].is_a?(String)
return match_winner(tournament)
else
tournament.each{|e|
winner(e)
}
end
end
tournament = [
[["one", "two"],["three", "four"]],
[["five", "six"],["seven", "eight"]]
]
puts winner(tournament).inspect
Which outputs:
[[["one", "two"], ["three", "four"]], [["five", "six"], ["seven", "eight"]]]
I tried different permutations and variations on this algorithm but I couldn't make it work correctly and return only the final winner.
Does anyone see anything obviously wrong here?
Now I'm calling winner.
I know that the question looks like it's answered, but I just did the same problem and I have to say that simply changing each to map didn't work for me, because, as the code posted, the result is an array of the first-round winners. What worked for me is:
def winner(tournament)
if tournament[0][0].is_a?(String)
return match_winner(tournament)
else
tournament.map!{|e| #use map!, because we need to apply winner() to new values
e=winner(e) #assign new value somewhere, so recursion can climb back
}
end
end
Maybe more experienced developers can explain why that is. Without these two tips it won't work.
And yes, I know "bang" is a bad coding style, danger danger high voltage, but it's my second day with Ruby and I wanted to get this to work.
And, to understand recursion, you have to understand recursion.
Looks like you want map, not each, and, as a commenter above notes, you didn't call winner in the above code.
When you call:
tournament.each {...}
that method actually returns the tournament, which is thus what winner returns.
What you want is to replace it with
tournament.map {...}
which returns a new array consisting of calling "winner" on each element of tournament.
Assuming you have 2^n number of games always and match_winner works ok:
def winner(game)
if game[0][0][0] == game[0][0][0][0]
match_winner( [ game[0], game[1] ] )
else
match_winner( [winner(game[0]), winner(game[1])] )
end
end

How do you modify array mapping data structure resultant from Ruby map?

I believe that I may be missing something here, so please bear with me as I explain two scenarios in hopes to reconcile my misunderstanding:
My end goal is to create a dataset that's acceptable by Highcharts via lazy_high_charts, however in this quest, I'm finding that it is rather particular about the format of data that it receives.
A) I have found that when data is formatted like this going into it, it draws the points just fine:
[0.0000001240,0.0000000267,0.0000000722, ..., 0.0000000512]
I'm able to generate an array like this simply with:
array = Array.new
data.each do |row|
array.push row[:datapoint1].to_f
end
B) Yet, if I attempt to use the map function, I end up with a result like and Highcharts fails to render this data:
[[6.67e-09],[4.39e-09],[2.1e-09],[2.52e-09], ..., [3.79e-09]]
From code like:
array = data.map{|row| [(row.datapoint1.to_f)] }
Is there a way to coax the map function to produce results in B that more akin to the scenario A resultant data structure?
This get's more involved as I have to also add datetime into this, however that's another topic and I just want to understand this first and what can be done to perhaps further control where I'm going.
Ultimately, EVEN SCENARIO B SHOULD WORK according to the data in the example here: http://www.highcharts.com/demo/spline-irregular-time (press the "View options" button at bottom)
Heck, I'll send you a sucker in the mail if you can fill me in on that part! ;)
You can fix arrays like this
[[6.67e-09],[4.39e-09],[2.1e-09],[2.52e-09], ..., [3.79e-09]]
that have nested arrays inside them by using the flatten method on the array.
But you should be able to avoid generating nested arrays in the first place. Just remove the square brackets from your map line:
array = data.map{|row| row.datapoint1.to_f }
Code
a = [[6.67e-09],[4.39e-09],[2.1e-09],[2.52e-09], [3.79e-09]]
b = a.flatten.map{|el| "%.10f" % el }
puts b.inspect
Output
["0.0000000067", "0.0000000044", "0.0000000021", "0.0000000025", "0.0000000038"]
Unless I, too, am missing something, your problem is that you're returning a single-element array from your block (thereby creating an array of arrays) instead of just the value. This should do you:
array = data.map {|row| row.datapoint1.to_f }
# => [ 6.67e-09, 4.39e-09, 2.1e-09, 2.52e-09, ..., 3.79e-09 ]

Combine array of array into all possible combinations, forward only, in Ruby

I have an array of arrays, like so:
[['1','2'],['a','b'],['x','y']]
I need to combine those arrays into a string containing all possible combinations of all three sets, forward only. I have seen lots of examples of all possible combinations of the sets in any order, that is not what I want. For example, I do not want any of the elements in the first set to come after the second set, or any in the third set to come before the first, or second, and so on. So, for the above example, the output would be:
['1ax', '1ay', '1bx', '1by', '2ax', '2ay', '2bx', '2by']
The number of arrays, and length of each set is dynamic.
Does anybody know how to solve this in Ruby?
Know your Array#product:
a = [['1','2'],['a','b'],['x','y']]
a.first.product(*a[1..-1]).map(&:join)
Solved using a recursive, so-called "Dynamic Programming" approach:
For n-arrays, combine the entries of the first array with each result on the remaining (n-1) arrays
For a single array, the answer is just that array
In code:
def variations(a)
first = a.first
if a.length==1 then
first
else
rest = variations(a[1..-1])
first.map{ |x| rest.map{ |y| "#{x}#{y}" } }.flatten
end
end
p variations([['1','2'],['a','b'],['x','y']])
#=> ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"]
puts variations([%w[a b],%w[M N],['-'],%w[x y z],%w[0 1 2]]).join(' ')
#=> aM-x0 aM-x1 aM-x2 aM-y0 aM-y1 aM-y2 aM-z0 aM-z1 aM-z2 aN-x0 aN-x1 aN-x2
#=> aN-y0 aN-y1 aN-y2 aN-z0 aN-z1 aN-z2 bM-x0 bM-x1 bM-x2 bM-y0 bM-y1 bM-y2
#=> bM-z0 bM-z1 bM-z2 bN-x0 bN-x1 bN-x2 bN-y0 bN-y1 bN-y2 bN-z0 bN-z1 bN-z2
You could also reverse the logic, and with care you should be able to implement this non-recursively. But the recursive answer is rather straightforward. :)
Pure, reduce with product:
a = [['1','2'],['a','b'],['x','y']]
a.reduce() { |acc, n| acc.product(n).map(&:flatten) }.map(&:join)
# => ["1ax", "1ay", "1bx", "1by", "2ax", "2ay", "2bx", "2by"]

Resources