Shane Carroll
Shane Carroll

Reputation: 37

How to find the index of element in two dimensional hash

I have a 2D array containing names and dates:

name_date_array = [[John Doe, 8/9/14], [Jane Smith, 9/4/14], [Mary Jane, 6/5/14],
[John Doe, 5/2/14]]

(I am rewriting this as it was unclear) I have two variables: patient_name andcollection_date. I am trying to find the index of the sub-array containing patient_name and a date that is smaller than 'collection_date'. Here is what I have from falsetru:

patient_name = browser.find_element(:xpath => ".//*[@id='dialog-modal-cancel-hl7-preview']/table/tbody/tr[2]/td[1]").text

collected_date = browser.find_element(:xpath => ".//*[@id='dialog-modal-cancel-hl7-preview']/table/tbody/tr[2]/td[4]").text
mo, da, yr = collected_date.split('/').map(&:to_i)
cd = [yr, mo, da]

name_admit_array.index { |name, date|
    m, d, y = date.split('/').map(&:to_i)
    dt = [y, m, d]
    name == patient_name and (dt <=> cd)<0
}

This works great, but the reason I am rewriting this (other than to save face as it was terribly written before) is that I have another question. collection_date is the date that a lab sample was collected for a particular client (patient_name). Each sub-array contains a patient's name, and their admission date. A patient can have several entries with the same name but different admission dates if they were a patient more than once.

I need to find the index of the sub-array that contains paitient_name and contains the admission date associated with the collection_date. This means that sub-array indexed needs to have the patient's name and the admission date that is before the collected date, but also closest to the collected date if there are more than one entries with admission dates before the collection date. I hope that makes sense.

For example, if the collection date is 9/3/14 I need to return the index of the sub-array [John Doe, 8/9/14] not [John Doe, 5/2/14] because the first contains the admission date associated with that collection (the stay during which the lab was collected from him). Clearly just requiring that the collection_date is larger than the admission date, dt, is not enough.

Upvotes: 0

Views: 69

Answers (1)

falsetru
falsetru

Reputation: 369424

You can use Array#index with a block. It will return the index of hte first item for which the block returns true:

name_date_array = [
  ['John Doe', '8/9/14'],
  ['Jane Smith', '9/4/14'],
  ['Mary Jane', '6/5/14'],
  ['John Doe', '5/2/14']
]

name_date_array.index { |name, date|
  m, d, y = date.split('/').map(&:to_i)
  dt = [y, m, d]
  name == 'John Doe' and (dt <=> [14, 8, 9]) < 0
}
# => 3

If you want get multiple indexes (Enumerable#each_with_index, Enumerable#select):

name_date_array.each_with_index.select { |(name, date), i|
  m, d, y = date.split('/').map(&:to_i)
  dt = [y, m, d]
  name == 'John Doe' and (dt <=> [14, 8, 9]) < 0
}.map { |x, i| i }
# => [3]

Upvotes: 1

Related Questions