Home > Back-end >  Ruby - 2 dimension array search
Ruby - 2 dimension array search

Time:01-13

I have the following 2 dimension array

data = [
 [5014031, nil], [5014032, nil], [5014033, 0], 
 [5014034, nil], [3014035, 1], [5014036, 1], 
 [5014037, 2], [5014038, nil], [5014039, 2], 
 [5014040, nil], [2014041, nil], [3014042, 2]
]

When I know the value of the 1st integer of one of these arrays e.g. 5014034, what would be the most efficient way to gain the next integer value where the 2nd element matches to nil? (e.g. I would expect 5014038 to be returned)

Thanks Scott

CodePudding user response:

Simple way, using #drop_while and #find_index:

data = [
  [5014031, nil], [5014032, nil], [5014033, 0],
  [5014034, nil], [5014035, 1], [5014036, 1],
  [5014037, 2], [5014038, nil], [5014039, 2],
  [5014040, nil], [5014041, nil], [5014042, 2]
]

remaining_arr = data.drop_while { |arr| arr[0] != 5014034 }[1 .. -1]
next_int = remaining_arr[remaining_arr.find_index { |arr| arr[1].nil? }][0]

CodePudding user response:

You could slice the array into two when the first element in the inner array matches 5014034. Extract the second resulting array and use find to look for the inner array whose second element is nil:

arr
  .slice_when { |a, _| a == 5014034 } # #<Enumerator: ...>
  .to_a                               # [[[5014031, nil], [5014032, nil], [5014033, 0], [5014034, nil]], [[5014035, 1], [5014036, 1], [5014037, 2], [5014038, nil], [5014039, 2], [5014040, nil], [5014041, nil], [5014042, 2]]]
  [1]                                 # [[5014035, 1], [5014036, 1], [5014037, 2], [5014038, nil], [5014039, 2], [5014040, nil], [5014041, nil], [5014042, 2]]
  .find { |_, b| b.nil? }             # [5014038, nil]
  [0]                                 # 5014038

Notice this method chaining might fail if there's no array in arr whose first object inside matches 5014034, and/or the same for find.

CodePudding user response:

If sorted then the following might be faster

data = [
 [5014031, nil], [5014032, nil], [5014033, 0], 
 [5014034, nil], [5014035, 1], [5014036, 1], 
 [5014037, 2], [5014038, nil], [5014039, 2], 
 [5014040, nil], [5014041, nil], [5014042, 2]
]

start_element = data.bsearch_index{ |a| a[0] >= 5014034 }

if start_element == nil || data[start_element] != 5014034
  puts "not found"
else
  data.slice((start_element 1)..).find { |a| a[1] == nil }[0]
end
  •  Tags:  
  • Related