在Ruby中,我如何找到数组元素中的一个的索引?

33

在 Ruby 2.4 中,如何找到一个数组中某个元素在另一个数组中最早出现的位置?也就是说,如果任何一个数组的元素出现在另一个数组中,我想得到第一个索引。我以为 find_index 可能会做到这一点,但是

a = ["a", "b", "c"]
# => ["a", "b", "c"]
a.find_index("a")
# => 0
a.find_index(["b", "c"])
# => nil
在上面的例子中,我期望看到输出“1”,因为元素“b”在数组“a”的索引1处出现。

你之前用 a.find_index("a") 找到了 "a"["a", "b", "c"] 中的索引,那么为什么你现在要用 a.find_index(["b", "c"]) 而不是 a.find_index("b") 来找 "b" 的索引呢?a.find_index(["b", "c"]) 是在寻找一个看起来像 ["b", "c"] 的元素,但实际上这个元素并不存在。它只是一个子数组,而不是一个元素。 - lurker
你是想要按顺序找到第一个出现的 b,c,还是只是在给定数组中找到第一个条目? - tadman
4个回答

27

find_index 接受一个元素作为输入。你可以通过类似以下方式来找到最小值:

a = ["a", "b", "c"]
to_find = ["b", "c"]
to_find.map {|i| a.find_index(i) } .compact.min # => 1

1
@CarySwoveland 对于 compact 我没有什么特别的看法;我经常看到它被使用,而且对我来说似乎很清晰明了。另外,提醒一下,[nil,nil,nil].compact.min 返回 nil。所以在我看来没有异常情况。 - Alejandro C.
我已经改正了。谢谢你指出问题,我的早先评论已经删除。 - Cary Swoveland

24
您可以使用find_index函数并从数组中传入所需的值:
a = ["a", "b", "c"]
p a.find_index('a')
p a.find_index('b')
p a.find_index('c')
# => 0
# => 1
# => 2
你可以使用map来获取你的a数组中的每个元素,然后获取对应于每个元素的索引:
p a.map{|e| a.find_index(e)}
# => [0, 1, 2]

另一种处理方法可能是使用Enumerable#each_with_index

a.each_with_index{|e,i| puts "Element: #{e}, Index: #{i}"}
# => Element: a, Index: 0
# => Element: b, Index: 1
# => Element: c, Index: 2

如果你想检查在["b", "c"]中每个元素在["a", "b", "c"]数组中的索引,你可以映射第一个数组,获取数组值,然后使用a,b,c来检查这些索引:

p ["b", "c"].map{|e| ["a", "b", "c"].find_index(e) }
# => [1, 2]

您还可以查看Array#indexEnumerable#find_index


有人情绪不稳。我已经投票以恢复宇宙的平衡。我认为这是因为它没有使用数组进行调用。 - tadman
问题要求返回一个单独的数字(索引),可能用于后续计算。你没有做到这一点。我认为这就是被踩的原因。另外,a.map{|e| a.find_index(e)} 没有任何价值。 - Cary Swoveland

15

你可以使用带有块的 Array#index 方法。

a = ['a', 'b', 'c']
a.index { |x| ['b', 'c'].include?(x) }
#=> 1

文档中的引用:

如果给定块而不是参数,则返回第一个使块返回true的对象的索引。如果找不到匹配项,则返回nil。


正如Cary在他的评论中指出的那样,将所有元素在a['b', 'c']中进行比较并不是最高效的算法(这将导致O(n*m))。根据两个数组的大小,如果构建一个更高效的数据结构可能更有意义。使用Set代替Array在创建set时具有一定的成本,但使块中的比较更快(总体上O(n+m)):

require 'set'

a = ['a', 'b', 'c']
set = Set.new(['b', 'c'])
a.index { |x| set.include?(x) }
#=> 1

如果 b = ['b', 'c'],则最好不要枚举 b 来查找与 a 匹配的元素。 如果 ab 分别包含 nm 个元素,并且在 a 中索引 i 的元素是第一个匹配 b 元素的元素(i <= n),则需要 i*m 次操作。 如果枚举 b,则需要 n*m 次操作。 因此,无论 nm 如何,比枚举 b 更快。 如果 n*m 很大,建议首先计算 require set; sb = b.to_set,然后使用 sb.include?(x) 来加速该操作。 - Cary Swoveland

0
你可以在数组 a 中找到数组 b 的所有元素的索引,并找到最小索引以找到数组 b 中的元素首次出现在数组 a 中的位置。
类似下面这样:
a = ["a", "b", "c"]
b = ["b", "c"]

b.map { |x| a.find_index(x) }.min
#=> 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接