【问题标题】:How to find the next element given a certain element in array给定数组中的某个元素,如何找到下一个元素
【发布时间】:2014-11-27 15:05:23
【问题描述】:

我编写了一个方法来获取数组中给定元素之后的下一个元素。如果我为该方法提供c,我希望它返回e;如果e,我希望它返回a等:

array = %w[a f c e]

def find_element_after(element, array)
  index = array.find_index(element) + 1
  array.at(index)
end

array.find_element_after("c", array)

如果我传入最后一个元素,我将得到nil。但我想返回第一个元素。

我可以用ifelse 解决这个问题。但是我想知道Ruby是否有更好的方法?

【问题讨论】:

  • 没有必要删除更改的文本。如果有什么不合理的地方,我们可以查看编辑历史记录。
  • 需要考虑的一点是,由于您使用的是线性搜索,array 的大小会变大,这将如何减慢速度。相反,我可能会在管理/维护该哈希的自定义类中使用某种链接列表或哈希。关键是您要搜索的内容,值是下一个元素。这将是一个非常一致的查找速度和稍慢的插入时间。
  • @theTinMan 感谢您指出这两件事。在这种情况下,我可能会有不到 100 个项目,这应该是微不足道的。不过很高兴知道。

标签: ruby arrays


【解决方案1】:

您可以修改您的方法,考虑数组大小,如下所示:

array = %w[a f c e]

def find_element_after(element, array)
  index = array.find_index(element) + 1
  array.at(index % array.size) # divide calculated index modulo array size
end

find_element_after('e', array)
# => "a"

如果你想让你的方法证明传递不是数组成员的参数,你可以这样做:

def find_element_after(element, array)
  index = array.find_index(element)
  array.at((index + 1) % array.size) if index
end
find_element_after('u', array)
# => nil

或:

def find_element_after(element, array)
  return nil unless array.include?(element)
  index = array.find_index(element)
  array.at(index % array.size)
end

如您所见,有许多可能的解决方案。随意尝试。

【讨论】:

    【解决方案2】:

    如果你传入最后一个元素,它确实有效。该索引被评估为最后一个索引,并从数组中检索lastindex + 1 处的元素返回nil

    问题是当您提供一个数组中不存在的元素时。正是这种情况会导致index 成为nil,然后当您在其上调用+ 1 时抛出NoMethodError

    要解决这种情况,请像这样定义您的方法:

    def find_element_after(element, array)
      index = array.find_index(element)
      array.at(index + 1) if index
    end
    

    这是一个演示它现在如何工作的演示 (run online):

    array = %w[a f c e]
    
    def find_element_after(element, array)
      index = array.find_index(element)
      array.at(index + 1) if index
    end
    
    p find_element_after("c", array) # element in the middle - prints "e"
    p find_element_after("e", array) # last element - prints "nil"
    p find_element_after("z", array) # element not present in the array - prints "nil" (no error)
    

    【讨论】:

    • 感谢您指出错误。问题是当最后一个元素被传递时,我永远不想返回 nil。我想返回第一个元素,本质上是一个圆圈。但这很容易,我现在明白了这个错误。
    【解决方案3】:

    您可以使用each_cons 使用对来迭代数组:

    def find_element_after(element, array)
      cons = array.each_cons(2).find { |i1, i2| i1 == element }
      cons.nil? ? array.first : cons.last
    end
    
    find_element_after('c', array)
    # => "e"
    find_element_after('e', array)
    # => "a"
    

    【讨论】:

      【解决方案4】:

      这里有一些其他方法可以做到这一点。

      #1 使用方法Array#rotate

      def nxt(arr, e)
        arr.rotate(arr.index(e)+1).first
      end
      
      arr = %w[a f c e]
      
      nxt(arr, 'a') #=> "f"
      nxt(arr, 'f') #=> "c"
      nxt(arr, 'c') #=> "e"
      nxt(arr, 'e') #=> "a"
      

      我认为这读起来不错,但它的缺点是创建了一个大小为arr 的临时数组。

      #2 使用Array#rotate 构造哈希

      h = Hash[arr.zip(arr.rotate(1))]
        #=> {"a"=>"f", "f"=>"c", "c"=>"e", "e"=>"a"}
      
      h['a'] #=> "f"
      h['f'] #=> "c"
      h['c'] #=> "e"
      h['e'] #=> "a"
      

      #3 使用Array#cycle 创建枚举器

      enum = arr.cycle
      
      def nxt(enum, v)
        until enum.next == v do
        end
        enum.next
      end
      
      nxt(enum, 'a') #=> "f"
      nxt(enum, 'f') #=> "c"
      nxt(enum, 'c') #=> "e"
      nxt(enum, 'e') #=> "a"
      

      如果要映射多个值,后两种方法应该相对有效。

      【讨论】:

        【解决方案5】:

        如果需要一个循环,如果最后一个通过则获取第一个元素

        def find_after(element, array)
          idx = array.index(element)
          array[idx - array.length + 1]
        end
        

        【讨论】:

          猜你喜欢
          • 2012-03-18
          • 2013-05-29
          • 1970-01-01
          • 2015-09-19
          • 2017-09-12
          • 1970-01-01
          • 2010-12-24
          • 2023-03-07
          • 1970-01-01
          相关资源
          最近更新 更多