我有一个带有排序数字的数组,例如
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
实现这一目标的好方法是什么?
答案 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值(nil
或false
)的所有元素,并保留块返回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 return
是raise
。
您可以通过这种方式“修复”您的第二个解决方案:
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 }
对待select
和false
,因此等同于
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
在获得第一个切片后终止切片。