Ruby在数组中查找下一个

17

有没有办法在 Ruby 数组中查找下一个元素?

代码:

# Find ALL languages
if !debug
  lang = Language.all
else
  lang = Language.where("id = ? OR id = ?", 22, 32)
end

# Get all elements
elements = Element.where("human_readable IS NOT NULL")

lang.each do |l|
  code = l.code.downcase
  if File.exists?(file_path + code + ".yml")
    File.delete(file_path + code + ".yml")
  end

  t1 = Time.now

  info = {}
  elements.each do |el|
    unless l.id == 1
      et = el.element_translations.where("language_id = ? AND complete = ?", l.id, true)
    else
      et = el.element_translations.where("language_id = ?", 1)
    end
    et.each do |tran|
      info[code] ||= {}
      info[code][el.human_readable] = tran.content.gsub("\n", "").force_encoding("UTF-8").encode!
    end
  end
  File.open(file_path + code + ".yml", "w", :encoding => "UTF-8") do |f|
    if f.write(info.to_yaml)
      t2 = Time.now

      puts code + ".yml File written"
      puts "It took " + time_diff_milli(t1, t2).to_s + " seconds to complete"
      # This is where I want to display the next item in the lang array
      puts lang.shift(1).inspect
      puts "*"*50
    end
  end
end

注意 puts lang.shift(1).inspect,在迭代 lang 的块内使用可能会导致一些问题。但也有可能不会。 - Mike Tunnicliffe
10
不可理解的问题,打负分。不要只是把代码扔给我们,然后期望我们修复它。在撰写问题时请付出一些努力。 - Theo
@Theo,我并没有向任何人“倾倒”代码...我只是在问一个问题...上面的代码是为了展示我所做的工作,以防有人需要参考它。 - dennismonsewicz
1
我认为问题在于你的问题看起来太简单了,以至于很难接受你实际上正在询问我们所认为的问题,即给定索引i处的项目x,如何读取索引i+1处的项目y。如果是这样,那么 x = array[i]y = array[i+1]。这甚至不是编程101,而是编程幼儿园,因此我们无法想象这就是你要问的问题。这并不是要冒犯,而是为了澄清。 - Mike Bethany
在你的代码中,始终使用描述性变量名。使用单个字母没有意义,实际上是糟糕的编码实践。花费额外的500毫秒来输入完整的单词,当你回去修复代码中的错误时,三个月后你会感谢自己的。 - Mike Bethany
在示例代码中,你试图在哪里找到数组中的下一个元素?去掉不必要的信息,展示一个简洁的问题示例。 - the Tin Man
5个回答

34

Array 包含 Enumerable,所以你可以使用 each_with_index

elements.each_with_index {|element, index|
   next_element = elements[index+1]
   do_something unless next_element.nil?
   ...

}

需要进行一些微调才能完全满足OP的要求,但是这是正确方法的一个很好的概述。 - Mike Tunnicliffe
1
我认为你的意思是 do_something unless next_element.nil? - Noz

30

如果你需要访问一个枚举(Enumerable)的元素和下一个元素,那么一种很好的迭代方式是使用each_cons方法:

arr = [1, 2, 3]
arr.each_cons(2) do |element, next_element|
   p "#{element} is followed by #{next_element}"
   #...
end

# => "1 is followed by 2", "2 is followed by 3".

正如Phrogz指出的那样,Enumerable#each_cons在Ruby 1.8.7+中可用;对于Ruby 1.8.6,您可以require 'backports/1.8.7/enumerable/each_cons'

正如@Jacob指出的那样,另一种方法是使用each_with_index


记录一下,each_cons只在1.8.7+版本(不在1.8.6中)可用。 - Phrogz
@Phrogz:确实!我通常会指出这一点。回答已更新。 - Marc-André Lafortune

5
arr[n..-1].find_index(obj) + n

4

根据 Marc-Andrés 的好回答,我想提供一个通用的答案,通过使用 nil 进行填充,为 所有 元素提供以下元素,包括最后一个元素:

arr = [1, 2, 3]
[arr, nil].flatten.each_cons(2) do |element, next_element|
   p "#{element} is followed by #{next_element || 'nil'}"
end

# "1 is followed by 2"
# "2 is followed by 3"
# "3 is followed by nil"

现在,我们可以为所有元素提供其前置元素:
arr = [1, 2, 3]
[nil, arr, nil].flatten.each_cons(3) do |prev_element, element, next_element|
  p "#{element} is preceded by #{prev_element || 'nil'} and followed by #{next_element || 'nil'}"
end

# "1 is preceded by nil and followed by 2"
# "2 is preceded by 1 and followed by 3"
# "3 is preceded by 2 and followed by nil"

4

或将此添加到您的项目中,然后您可以在任何数组上调用next_item(item)方法。

class Array
  def next_item(item)
     self[self.find_index(item) + 1] unless self.find_index(item).nil?
  end
end

关于我提供的答案中self的使用说明。我承认,在某种意义上,使用self是多余和不必要的。但这是我的偏好,更频繁地使用self可以使代码更加明显,特别是对初级程序员来说。简单性对我来说很重要,即使需要更多字符。


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