Okiba - 6 months ago 9
Ruby Question

Checking cell combination in a table

I'm trying to implement an algorithm for table verification, but I'm confused with the multiple choices Ruby supplies for working with arrays and hashes and I need help putting it all together. Consider this table as example:

``````| A | B | C |
-------------
| 1 | 2 | 3 |
| 1 | 2 | 4 |
| 5 | 6 | 7 |
| 1 | 1 | 3 |
``````

My method should count the number of occurrences of a specific cell combination. For example:

``````match_line([A => 1, C => 3])
``````

The results should be
`2`
, as this combination exists in both the first row and the last one.
What I did so far is to create an
`hash`
variable that hold column indexing like so:

``````[A => 0, B => 1, C=> 2]
``````

And I also have an array list which holds all the above table rows like so:

``````[[1, 2, 3], [1, 2, 4], [5, 6, 7], [1, 1, 3]]
``````

The logic looks like that - the
`match_line`
method above specific the user wants to match a row where column A has the
`1`
value in it and column C has the
`3`
value in it. Based on my index hash, the A column index is
`0`
and C index is
`2`
. Now for each array (row) in the array list, if index 0 equals
`1`
and index 2 equals
`3`
like the user requested , I add +1 to a counter and keep going over the other array row until I'm over.

I tried to form it into code, but I ended with a way that seems very not efficient of doing so, I'm interested to see your code example to see perhaps Ruby has inner Enumerable methods that I'm not aware of to make it more elegant.

First, you should use the best available structure to describe your domain :

``````data = [[1, 2, 3], [1, 2, 4], [5, 6, 7], [1, 1, 3]]

@data_hashes = data.map do |sequence|
{ 'A' => sequence[0], 'B' => sequence[1], 'C' => sequence[2] }
end
``````

Second, I think you should use a real Hash as input for match_line :

``````# replace match_line([A => 1, C => 3]) with
match_line({'A' => 1, 'C' => 3})
``````

Now you're all set for an easy implementation using `Enumerable#select` and `Array#size`

``````def match_line(match)
@data_hashes.select { |row|
match.all? { |match_key, match_value|
row[match_key] == match_value
}
}.size
end
``````

EDIT: Dynamically create Hash from column names

``````columns = ['a', 'b', 'c']
data = [[1, 2, 3], [1, 2, 4], [5, 6, 7], [1, 1, 3]]

@data_hashes = data.map do |row|
Hash[columns.zip(row)]
end
``````
Source (Stackoverflow)