Reputation:
I'm using Ruby 2.4. I have an array of strings, which I want to add to an array of arrays. So for example, if I have two arrays,
["a", "b", "c"]
["1", "2", "3"]
As I gradually add these arrays into my array of arrays, my resulting array of arrays will look like
[["a", "1"], ["b", "2"], ["c", "3"]]
I achieve this using the below
if data_cols.size == 0
data_cols = parts
else
if parts.size > data_cols.size
num_elts = data_cols[0].size
(0..(parts.size - data_cols.size)).each do |i|
arr = Array.new(num_elts)
data_cols.push(arr)
end
end
data_cols = data_cols.zip(parts).map(&:flatten)
end
My question is, how do I figure out if I have already added an array of strings? So for isntance, if I were adding
["a", "b", "c"]
["1", "2", "3"]
["a", "b", "c"]
The result would be
[["a", "1"], ["b", "2"], ["c", "3"]]
since I tried to add '["a", "b", "c"]' a second time. Right now, the result is
[["a", "1", "a"], ["b", "2", "b"], ["c", "3", "c"]]
Upvotes: 0
Views: 62
Reputation: 54263
You could use a set to keep unique rows :
require 'set'
rows = Set.new
rows << ["a", "b", "c"]
rows << ["1", "2", "3"]
rows << ["a", "b", "c"]
columns = rows.to_a.transpose
p columns
#=> [["a", "1"], ["b", "2"], ["c", "3"]]
Note that since Ruby 1.9, Set uses a Hash internally so the order is preserved (related answer here). With your version (2.4), the order will be preserved. It isn't guaranteed to work on any other Ruby implementation (e.g. Ruby 1.8, Rubinius or JRuby) though.
Upvotes: 1
Reputation: 9497
how do I figure out if I have already added an array of strings?
Here we check if check
has already been added to array
:
check = ["a", "b", "c"]
array = [["a", "1"], ["b", "2"], ["c", "3"]]
array.transpose.include? check #=> true
steps:
a = array.transpose #=> [["a", "b", "c"], ["1", "2", "3"]]
a.include? check #=> true
Upvotes: 1
Reputation: 121010
Just uniq
your input in advance:
data.uniq.reduce(&:zip).map(&:flatten)
Upvotes: 0
Reputation: 211670
You're not using zip
correctly. Here's a reworked, more minimal version:
data = [
["a", "b", "c"],
["1", "2", "3"],
["a", "b", "c"]
]
# Take first row of data as headers, group the rest together
headers, *rows = data
rows.map do |row|
headers.zip(row)
end.to_a
# => [[["a", "1"], ["b", "2"], ["c", "3"]], [["a", "a"], ["b", "b"], ["c", "c"]]]
This combines two three-element arrays using zip
and reworks each row to be in the right format.
If you're looking to exclude duplicates, you can always pre-process with:
data.uniq!
Do that before splitting out the headers and you won't have any duplicate entries, or if the headers are repeated they're ignored.
If you want to only exclude the headers from the data, then you can do this:
rows.delete(headers)
Sometimes when trying to solve simple problems like this it's easy to get tripped up in your own code, especially as you're going against the grain and fighting Ruby to get a solution. Things like if data_cols.size == 0
and then initializing it is a sign you're over-complicating things, though sometimes those signs are easy to miss.
Upvotes: 0