user7055375
user7055375

Reputation:

How do I figure out if I have already added an array of strings to my array of arrays?

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

Answers (4)

Eric Duminil
Eric Duminil

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

Sagar Pandya
Sagar Pandya

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

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

Just uniq your input in advance:

data.uniq.reduce(&:zip).map(&:flatten)

Upvotes: 0

tadman
tadman

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

Related Questions