红宝石bsearch,找到最后一次出现

时间:2019-09-19 22:25:07

标签: ruby

是否有一种方法可以使bsearch返回最后一次出现而不是第一次出现?

例如:

arr = [1,2,3,4,4,5]
arr.bsearch { |x| 4 - x } # this returns the first 4

hash = {
  1 => {
    "foo" => "bar",
    "test" => "abc"
  },
  4 => {
    "foo" => "bar2",
    "test2" => "def"
  },
  5 => {
    "test2" => "abc"
  }
}

hash.keys.bsearch { |x| !hash[x]['test2'].nil? } # this returns 4, but I want it to return 5

我想找到'test'2不为空的最后一次出现。

3 个答案:

答案 0 :(得分:0)

您可以在此处尝试使用变量 y 进行存储。

hash.keys.bsearch {| x | y = x如果!hash [x] ['test2']。nil? }

答案 1 :(得分:0)

您可以反转哈希并对其运行bsearch。用您的哈希值:

hash.reverse_each.to_h.keys.bsearch { |x| !hash[x]['test2'].nil? }
=> 5

This post将阐明bsearch的工作方式。

答案 2 :(得分:0)

bsearch所使用的格式(采用产生整数的块)不会返回相同值中的第一个;它返回偶然发现的任何东西,因为它认为它们是相同的。例如:

[1, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3, 4, 5].bsearch { |e| 2 - e.to_i }
# => 2.5

返回的值位于2.x值的中间,仅仅是因为bsearch首先偶然发现了它。如果要返回第一个值,则必须使用另一种形式,其中该块产生布尔值。从那里开始,对其进行最后的工作很简单。例如:

array = [1, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3, 4, 5]
indices = array.size.times.to_a
first_index = indices.bsearch { |i| array[i].to_i >= 2 }
last_index = indices.reverse.bsearch { |i| array[i].to_i <= 2 }
array[first_index..last_index]
# => [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7]

如果您不需要索引,而是第一个和最后一个元素本身,那么就足够了:

first_element = array.bsearch { |e| e.to_i >= 2 }
last_element = array.reverse.bsearch { |e| e.to_i <= 2 }

对于问题的哈希部分,您的问题很奇怪。对于其中块产生布尔值的bsearch格式(如您在该示例中使用的那样),强制性的是,对于要搜索的元素之前的任何元素,块均产生false,而{{1} }之后。 (类似地,当block产生整数时,它应返回负值,后跟零,后跟正值。换句话说,应该根据要搜索的谓词对数组进行排序。)因此,根据定义,最后一个元素符合您的条件(所有没有true的元素都在所有带有"test1"的元素之前)必须"test1"