选择项目的有效方式<排序数组的值

时间:2015-10-28 02:19:32

标签: arrays ruby sorting select

我有一个带有排序数字的数组,例如

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

有没有办法选择项目< 5,没有遍历整个阵列? 例如。以下将遍历整个数组并检查每个项目。但是,对于已排序的数组,只要它击中项目> = 5就会中断。

arr.select { |p| p < 5 }

我尝试过休息时的变体,然后返回并没有成功。

arr.select { |p| p < 5; break  if p >= 5 } # = nil
arr.select { |p| p < 5; next   if p >= 5 } # = []
arr.select { |p| p < 5; return if p >= 5 } # LocalJumpError

实现这一目标的好方法是什么?

4 个答案:

答案 0 :(得分:3)

我认为您可以使用take_while方法。

答案 1 :(得分:0)

以下是另一种方法:

  > arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
  #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
  > index = arr.index(5)
  #=> 4
  > arr[0..index]
  #=> [1, 2, 3, 4, 5]

答案 2 :(得分:0)

首先,为什么你的解决方案不起作用? select接受一个块,它抛弃了块返回false-ish值(nilfalse)的所有元素,并保留块返回true的所有元素 - 价值。

arr.select { |p| p < 5; break  if p >= 5 } # = nil

在这里,您调用p < 5但是您只需忽略其返回值。在Ruby中,块的返回值是块内计算的最后一个表达式的值。此处评估的最后一个表达式是break if p >= 5。由于没有else大小写,它将为小于5的所有元素返回nil(即false,即表示“不保留此元素”),然后它将{ {1}}(表示“中止并返回break”)。

IOW:你告诉nil扔掉所有小于5的元素然后中止。

select

在这种情况下,再次,您为所有小于5的元素返回arr.select { |p| p < 5; next if p >= 5 } # = [] ,对于所有大于或等于5的元素,您将参数返回到nil ...但是没有参数,因此,对于大于5的所有元素,您也返回next

IOW:你告诉nil扔掉所有小于5的元素然后你告诉它扔掉所有大于或等于5的元素,换句话说,你告诉它扔掉所有元素...... 你仍在迭代整个数组。

无论如何这没有多大意义。 select隐含在一个块中,就像方法中隐含next一样。 (实际上,return用于阻止next方法的块,所以你所做的就是添加一个多余的关键字。

return

再次,和以前一样......你告诉arr.select { |p| p < 5; return if p >= 5 } # LocalJumpError 扔掉所有小于5的元素,然后你从封闭方法中select。但是没有封闭方法,所以Ruby returnraise

您可以通过这种方式“修复”您的第二个解决方案:

LocalJumpError

即。对于小于5的元素,你需要实际返回arr.select { |p| if p < 5 then true else next end } (或者是真实的东西)。但是,就像我说的那样,无论如何都隐含true,所以你可以把它留下来,这意味着这是相当于

next

其中,由于arr.select { |p| if p < 5 then true else nil end } 对待selectfalse,因此等同于

nil

这当然与

相同
arr.select { |p| if p < 5 then true else false end }

其中,由于arr.select { |p| p < 5 } <的对称性与

相同
>

无论如何,在排序数组中搜索的正确解决方案是使用二进制搜索,它不需要在所有中迭代数组,并且只需要O(log(n)比较:

arr.select(&5.method(:>))

这将搜索“最后一个小于5的数字的下一个最大索引右边的元素的索引”。然后,您可以使用Array#[]提取所需的元素片

arr.bsearch_index(&5.method(:<=))

请注意,arr[0...arr.bsearch_index(&5.method(:<=))] new in 2.3.0,我相信,在此之前,您可以使用Range#bsearch instead

Array#bsearch_index

答案 3 :(得分:0)

您也可以使用Enumerable#lazy Enumerable#slice_while使用Pikaday来执行此操作:

arr.lazy.slice_before { |i| i >= 5 }.first
  #=> [1, 2, 3, 4] 

通过使slice_before延迟,first在获得第一个切片后终止切片。