我有一个已排序的唯一数组,并希望有效地在其中插入一个不在数组中的元素:
a = [1,2,4,5,6]
new_elm = 3
insert_at = a.bsearch_index {|x| x > new_elm } # => 2
a.insert(insert_at, new_elm) # now a = [1,2,3,4,5,6]
方法bsearch_index
不存在:只有bsearch
,它返回匹配元素而不是匹配元素的索引。有没有内置的方法来实现这个目标?
答案 0 :(得分:10)
您可以使用Enumerator
返回的each_with_index
对象返回[value, index]
对的嵌套数组,然后对该数组执行二进制搜索:
a = [1,2,4,5,6]
new_elm = 3
index = [*a.each_with_index].bsearch{|x, _| x > new_elm}.last
=> 2
a.insert(index, new_elm)
修改强>
我使用长度为1e6 - 1
的数组运行了一些简单的基准来回答你的问题:
require 'benchmark'
def binary_insert(a,e)
index = [*a.each_with_index].bsearch{|x, _| x > e}.last
a.insert(index, e)
end
a = *1..1e6
b = a.delete_at(1e5)
=> 100001
Benchmark.measure{binary_insert(a,b)}
=> #<Benchmark::Tms:0x007fd3883133d8 @label="", @real=0.37332, @cstime=0.0, @cutime=0.0, @stime=0.029999999999999805, @utime=0.240000000000002, @total=0.2700000000000018>
考虑到这一点,您可以考虑尝试使用堆或trie而不是数组来存储您的值。特别是堆具有恒定的插入和移除时间复杂性,使其成为大型存储应用的理想选择。在这里查看这篇文章:Ruby algorithms: sorting, trie, and heaps
答案 1 :(得分:9)
如何使用SortedSet
?:
require 'set'
a = SortedSet.new [1,2,4,5,6]
new_elm = 3
a << new_elm # now a = #<SortedSet: {1, 2, 3, 4, 5, 6}>
SortedSet使用rbtree
实现。我做了以下基准测试:
def test_sorted(max_idx)
arr_1 = (0..max_idx).to_a
new_elm = arr_1.delete(arr_1.sample)
arr_2 = arr_1.dup
set_1 = SortedSet.new(arr_1)
Benchmark.bm do |x|
x.report { arr_1.insert(arr_1.index { |x| x > new_elm }) }
x.report { arr_2.insert([*arr_2.each_with_index].bsearch{|x, _| x > new_elm}.last) }
x.report { set_1 << new_elm }
end
end
得到以下结果:
test_sorted 10_000
# => user system total real
# => 0.000000 0.000000 0.000000 ( 0.000900)
# => 0.010000 0.000000 0.010000 ( 0.001868)
# => 0.000000 0.000000 0.000000 ( 0.000007)
test_sorted 100_000
# => user system total real
# => 0.000000 0.000000 0.000000 ( 0.001150)
# => 0.000000 0.010000 0.010000 ( 0.048040)
# => 0.000000 0.000000 0.000000 ( 0.000013)
test_sorted 1_000_000
# => user system total real
# => 0.040000 0.000000 0.040000 ( 0.062719)
# => 0.280000 0.000000 0.280000 ( 0.356032)
# => 0.000000 0.000000 0.000000 ( 0.000012)
答案 2 :(得分:3)
&#34;方法bsearch_index
不存在&#34;:Ruby 2.3引入bsearch_index。 (感谢在方法名称存在之前获取方法名称)。
答案 3 :(得分:2)
试试这个
var animal = {};
var one = 'sound';
var two = 'age';
animal['cat'] = {};
animal['cat'][one] = 'meow';
animal['cat'][two] = 9;
console.log(animal);
这使用(0...a.size).bsearch { |n| a[n] > new_element }
上定义的bsearch
来搜索数组,从而返回索引。
性能优于Range
,它会实现each_with_index
临时数组元组,从而阻塞垃圾回收。
答案 4 :(得分:1)
Ruby 2.3.1引入了bsearch_index,因此现在可以通过这种方式解决问题:
a = [1,2,4,5,6]
new_elm = 3
index = a.bsearch_index{|x, _| x > new_elm}
=> 2
a.insert(index, new_elm)
答案 5 :(得分:-2)
index
方法接受一个块,并返回块为真的第一个索引
a = [1,2,4,5,6]
new_elem = 3
insert_at = a.index{|b| b > new_elem}
#=> 2
a.insert(insert_at, new_elm)
#=>[1,2,3,4,5,6]