captainrad
captainrad

Reputation: 3830

Rails: loop comparing two arrays and pushing matches to new array

I have two arrays that I need to check against each other. When a match is found I need to unset the value from the first array and push that value to a new array.

Here is an example:

First Array import_data

["mario", "blue", "SGC", "CJ672PA0"], 
["solid snake", "green", "NID", "VI6965KD"], 
["samus", "maroon", "TRUST", "DNYU6539"], 
["deckard cain", "purple", "JAFA", "SJW252MZ"],
["wedge", "yellow", "WALTER", "UJ28NVM1"]

Second Array current_data

["gordon", "orange", "DRONE", "OGJR8C0D"], 
["samus", "black", "TRUST", "DNYU6539"], 
["commander shepard", "red", "WHX", "TH985OI3"]

Notice that "samus" appears in both arrays with all the same data but a change to the color.

My intent is to loop through import_data and check the last index of each item in the array (the 8-digit "id") and compare that against current_data. Each time a "match" is found (based on the 8-digit "id") I want to push that item into a new array update_data and then I want to unset that match in the import_data array.

The problem is that both arrays are of differing lengths. So as soon as my loop goes beyond the length of one item it can no longer check that index which results in an error.

My code essentially looks like this:

import_data.each_with_index do |data, index|
  if data[3] == current_data[index].id
    # @update_data << somehow push all of the data
  end
end

The reason this isn't working is because the length of import_data is longer than that of current_data. This results in the error:

"undefined method `id' for nil:NilClass"

Ideally the end result would be as follows:

"samus" has been removed from the import_data array and pushed to the update_data array

import_data array after loop

["mario", "blue", "SGC", "CJ672PA0"], 
["solid snake", "green", "NID", "VI6965KD"], 
--- 
["deckard cain", "purple", "JAFA", "SJW252MZ"],
["wedge", "yellow", "WALTER", "UJ28NVM1"]

Newly populated array update_data

 ["samus", "maroon", "TRUST", "DNYU6539"]

Upvotes: 1

Views: 1437

Answers (2)

Alejandro Babio
Alejandro Babio

Reputation: 5229

Since the answer of Prakash works, I think this is more straightforward:

import_data = [
  ["mario", "blue", "SGC", "CJ672PA0"], 
  ["solid snake", "green", "NID", "VI6965KD"], 
  ["samus", "maroon", "TRUST", "DNYU6539"], 
  ["deckard cain", "purple", "JAFA", "SJW252MZ"],
  ["wedge", "yellow", "WALTER", "UJ28NVM1"]
]
current_data = [
  ["gordon", "orange", "DRONE", "OGJR8C0D"], 
  ["samus", "black", "TRUST", "DNYU6539"], 
  ["commander shepard", "red", "WHX", "TH985OI3"]
]

current_ids = current_data.map {|c| c[3]}

update_data = import_data.inject([]) do |result, data|
  result << import_data.delete(data) if current_ids.include?(data[3])
  result
end

After run you get:

update_data = [
  ["samus", "maroon", "TRUST", "DNYU6539"]
]
import_data = [
  ["mario", "blue", "SGC", "CJ672PA0"], 
  ["solid snake", "green", "NID", "VI6965KD"], 
  ["deckard cain", "purple", "JAFA", "SJW252MZ"],
  ["wedge", "yellow", "WALTER", "UJ28NVM1"]
]

I hope it helps.

Upvotes: 3

Prakash Murthy
Prakash Murthy

Reputation: 13067

One way to accomplish what you are doing:

import_data = [ 
                ["mario", "blue", "SGC", "CJ672PA0"], 
                ["solid snake", "green", "NID", "VI6965KD"], 
                ["samus", "maroon", "TRUST", "DNYU6539"], 
                ["deckard cain", "purple", "JAFA", "SJW252MZ"],
                ["wedge", "yellow", "WALTER", "UJ28NVM1"]
              ]

current_data = [
                 ["gordon", "orange", "DRONE", "OGJR8C0D"], 
                 ["samus", "black", "TRUST", "DNYU6539"], 
                 ["commander shepard", "red", "WHX", "TH985OI3"]
                ]

Find the keys for both the arrays:

import_data_keys = import_data.map { |x| x[3] }
=> ["CJ672PA0", "VI6965KD", "DNYU6539", "SJW252MZ", "UJ28NVM1"]
current_data_keys = current_data.map { |x| x[3] }
=> ["OGJR8C0D", "DNYU6539", "TH985OI3"]

Find the common keys by intersecting these two arrays:

common_keys = import_data_keys & current_data_keys
=> ["DNYU6539"]

Use common_keys to delete from import_data and push to update_data.

common_keys.each do |key|
  import_data.each_with_index do |data, index|
    if data[3] == key
      update_data << import_data[index]
      import_data.delete_at(index)
      break
    end
  end
end

Note: The break statement is for stopping with that iteration after the element is found and processed.

Upvotes: 1

Related Questions