【问题标题】:Return sub-array based on hash key/value range?基于哈希键/值范围返回子数组?
【发布时间】:2013-11-02 05:27:03
【问题描述】:

我有一个排序好的元素数组:

array = ["A", "B", "C", "D", "E"]

我定义了一系列元素,其中“key”是开始元素,“value”是结束元素:

range_1 = {"C" => "D"}
range_2 = {"B" => "E"}

如何编写代码,根据上面数组解析的范围返回子数组?

result_1 = ["C", "D"]
result_2 = ["B", "C", "D", "E"]

【问题讨论】:

  • 如果你想在 Ruby 中表达范围,你应该使用("C".."D") 而不是带有单个键/值的散列。即使是带有start: 'C', end: 'D' 的散列也是表示数据的更好方式。
  • 我刚开始使用 Ruby,我喜欢 Hash => 表示法。看来我也会喜欢范围符号。
  • @flyer:如果你唯一的工具是一把锤子,那么每一个问题看起来都像是一个破碎的拇指。 :)
  • 请检查子数组的另一个变体:stackoverflow.com/q/19732759/743027

标签: ruby arrays


【解决方案1】:

假设你的数组元素是唯一的:

array = ["A", "B", "C", "D", "E"]

range_1 = {"C" => "D"}
range_2 = {"B" => "E"}

def subarray(array, range)
  from, to = range.first
  idx_from = array.index(from)
  idx_to = array.index(to)
  array[idx_from..idx_to]
end

subarray(array, range_1) # => ["C", "D"]
subarray(array, range_2) # => ["B", "C", "D", "E"]

【讨论】:

    【解决方案2】:
    result_1 = array[array.index(range_1.keys.first)..array.index(range_1.values.first)]
    result_2 = array[array.index(range_2.keys.first)..array.index(range_2.values.first)]
    

    【讨论】:

      【解决方案3】:

      你这样做有异味:

      • 而不是使用类似的东西:

        range_1 = {"C" => "D"}
        range_2 = {"B" => "E"}
        

        我会选择使用真实范围:

        range_1 = 'C' .. 'D'
        range_2 = 'B' .. 'E'
        

        然后我可以不用使用array,因为将范围转换为连续值数组非常容易。

        range_1.to_a # => ["C", "D"]
        range_2.to_a # => ["B", "C", "D", "E"]
        
        [*range_1] # => ["C", "D"]
        [*range_2] # => ["B", "C", "D", "E"]
        
      • 如果array 中的值不是真正连续的,如示例所示,那么我将使用索引值:

        array = ["A", "B", "C", "D", "E"]
        range_1 = 2 .. 3
        range_2 = 1 .. 4
        

        这使得检索值变得容易:

        array = ["A", "B", "C", "D", "E"]
        range_1 = 2 .. 3
        range_2 = 1 .. 4
        
        array[range_1] # => ["C", "D"]
        array[range_2] # => ["B", "C", "D", "E"]
        

      如果您需要使用来自array 的实际值作为索引的符号名称,这将变得更加困难,类似于您现在正在做的事情,但如果您使用的是 Web 前端,那就还不错。用户的大脑和眼睛是一笔不错的资产。

      由于用例定义不明确,我们无法真正推荐更好的解决方案。我怀疑在这种情况下,您已经确定某个算法是最好的,现在您正试图使其发挥作用,但是当您感觉到房间的角落正在逼近时,熵就开始了。这是基于 a 的分析多年查看代码,而不是草率判断。


      但是像这样的东西不是 ["A","B","C","D"]["B".."D"]。我进入 '[]': can't convert String into Integer

      需要考虑的其他一点是,哈希就像数组一样,只是它们允许使用values_at 更轻松地进行随机访问。

      考虑一下:

      array = %w[a b c d x y z]
      hash = Hash[array.map.with_index{ |e, i| [e, i] }]
      hash # => {"a"=>0, "b"=>1, "c"=>2, "d"=>3, "x"=>4, "y"=>5, "z"=>6}
      

      哈希值不需要整数,它们可以是 nil 或布尔值,我根据需要使用了其中的任何一种。我在这里使用它们来使正在发生的事情更加明显。最大的胜利是哈希允许我们以任何顺序提取内容,只需指定该顺序是什么。如果它是一个范围或一组范围,我们仍然可以按我们想要的顺序提取值。

      这是一个使用单个范围的简单示例:

      hash.values_at(*('a' .. 'd')) # => [0, 1, 2, 3]
      hash.values_at(*('x' .. 'z')) # => [4, 5, 6]
      

      这些是复合范围示例:

      hash.values_at(*('a' .. 'c'), *('x' .. 'z')) # => [0, 1, 2, 4, 5, 6]
      hash.values_at(*('x' .. 'z'), *('a' .. 'c')) # => [4, 5, 6, 0, 1, 2]
      

      请注意,在第二个范围内,范围是相反的,并且值反映了这一点。

      还要注意范围被分解为数组。数组可以来自任何地方,只要元素与哈希中的键匹配,您就会看到返回的值与数组的顺序相同。

      【讨论】:

      • 感谢有用的提示。不幸的是,这不能使用,因为我没有连续的数组元素,我需要通过字符串定义“范围”。建议的["A","B","C"][1..2] 效果很好,但这样的东西不适合["A","B","C","D"]["B".."D"]。我得到in '[]': can't convert String into Integer
      • 正确,您不能使用 alpha 范围,因为 [] 仅支持整数。您的示例数组需要反映您的现实;如果数组中没有连续的值,请确保已注明。哈希和数组切片可以玩一些非常有趣的技巧,哈希切片并不关心数组中的内容是否有序。将按照指定键的顺序检索值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 2015-06-13
      • 2017-07-09
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多