3

I have an array:

["a", "b", "c", "d"]

How do I figure out the index of the first element of the above array to occur within a second array:

["next", "last", "d", "hello", "a"]

The index of the first element from the first array to occur within the above array would be 2; "d" belongs to the first array and occurs at position 2.

1
  • From the example it seems that you want the index of the first element in the second array that occurs in the first array, but that's not what you said. Is not "a"(not "d") "the first element from the first array to occur within the above [second] array"? Commented Mar 12, 2017 at 2:31

3 Answers 3

4

There's a couple of ways to do this, but the naive approach might work well enough to get going:

tests = ["a", "b", "c", "d"]
in_array = ["next", "last", "d", "hello", "a"]

in_array.each_with_index.find do |e, i|
  tests.include?(e)
end
# => ["d", 2]

You can speed this up by making tests a Set which avoids a lot of O(N) lookups:

tests = Set.new([ ... ])

The same code will work with include? but that's now much faster on longer lists.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. So how do I get the actual index? I tried "found_index = in_array.each_with_index.find do |e, i| tests.include?(e)[1] end" but I keep getting a "NoMethodError: undefined method `[]' for false:FalseClass" error.
If you want, you can just break out the results of this operation: found_test, found_index = in_array.each_with_index... where you'll get two variables instead of an array of two elements. Remember include? returns true or false so you can't reference it that way. The other way would be found = in_array... and then found[0] and found[1] which is probably what you were thinking of, but doing prematurely.
0

This approach, wrapped in a method, returns an array containing all indexes of common elements between two arrays.

def find_positions(original_array, look_up_array)
  positions_array = []
  original_array.each do |x|
    if look_up_array.index(x) != nil
      positions_array << look_up_array.index(x)
    end
  end
  positions_array
  # positions_array.first => for the first matched element
end

If you want only the first matched element you could return positions_array.first but this way you'll not avoid the extra lookups.

PS: you could also use #collect and avoid the extra array (positions_array)

Comments

-1

You can iterate through the array you want to be compared and use .select or .find iterator method. .find will select the first element match in the arrays while .select will match all elements in the arrays. If you want to add the index in the selection you can add .each_with_index. '.index(a)' returns the element if present else it will return nil.

alphabet = %w(a b c d)
%w(next last d hello a).each_with_index.find {|a, _index| alphabet.index(a) }
 => ["d", 2]
%w(next last d hello a).each_with_index.select {|a, _index| alphabet.index(a) }[0]
 => ["d", 2]
# if you just need the index of the first match
%w(next last d hello a).index {|a| alphabet.index(a) }
 => 2 

5 Comments

This answer can be improved by adding a description to code in your answer.
Hi, You're choosing every element from the array where somethinng is found, but I only want the first element to be found.
if you just need the first element you can add an [0] at the end of the block or iterate with find instead of select which would be a bit cleaner.
That still doesn't 'return an index. It returns something that looks like '["c", 2]'.
Sorry about that, I miss understood that you just needed the index returned. I have just updated my answer to return just the index.

Your Answer

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