1

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

6
  • 1
    Most efficient way to do this query once or most efficient to do this repeatedly? Is this array sorted by 1st integer? Commented Jan 12, 2022 at 9:13
  • Hi @ChristopherOezbek It's only going to happen once per page request and the array can have 1000's of entries and there's no sort. Commented Jan 12, 2022 at 9:15
  • Will the array be the same for all page requests? Or will each request operate on another array? Because if all requests operate on the same array then it would make sense to use a different data structure that is optimized for reading the data. And another question if the input was 5014040 what is then the "next integer"? 2014041 because it is next in the array? Or or nil because there is no bigger integer than 5014040 with a 2nd element being nil? Commented Jan 12, 2022 at 9:28
  • @spickermann All pages will have different arrays and if the known id was 5014040 the next integer would be 2014041 as it has the next nil. Commented Jan 12, 2022 at 9:36
  • What do you mean by all pages having different arrays? Does that mean that all users operate on the same data when they request the same page? Is the array generated with data from the database? Would it be possible to write an optimized database query instead? Commented Jan 12, 2022 at 9:52

3 Answers 3

3

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..]
next_int = remaining_arr[remaining_arr.find_index { |arr| arr[1].nil? }][0]

Alternatively:

data
  .drop_while { |x| x[0] != 5014034 }[1..]
  .drop_while { |x| !x[1].nil? }[0][0]
# => 5014038
Sign up to request clarification or add additional context in comments.

2 Comments

remaining_arr.find { |a, b| b.nil? }[0] or remaining_arr.rassoc(nil)[0] works too. You also have to remove the first element from remaining_arr to exclude it from the 2nd search. (otherwise you'll return [5014034, nil] instead of [5014038, nil])
Thanks! Incorporated this suggestion.
2

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.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.