bisect 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rspec +1 -0
- data/LICENSE.MIT +19 -0
- data/README.md +60 -0
- data/bisect.gemspec +19 -0
- data/lib/bisect.rb +78 -0
- data/lib/bisect/core_ext.rb +9 -0
- data/spec/bisect_spec.rb +115 -0
- metadata +70 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-r./lib/bisect/core_ext
|
data/LICENSE.MIT
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 Conrad Irwin <conrad@rapportive.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
The bisect gem provides helpers for dealing with sorted Arrays.
|
2
|
+
|
3
|
+
Installation
|
4
|
+
============
|
5
|
+
|
6
|
+
```
|
7
|
+
gem install bisect
|
8
|
+
```
|
9
|
+
|
10
|
+
If you're using Bundler, add `gem 'bisect'` to your Gemfile.
|
11
|
+
|
12
|
+
Usage
|
13
|
+
=====
|
14
|
+
|
15
|
+
There are two functions that you need to know about `Bisect.insort` and `Bisect.bisect`.
|
16
|
+
|
17
|
+
`Bisect.insort` adds a new element to the Array, but keeps the Array sorted:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'bisect'
|
21
|
+
a = [1, 2, 4]
|
22
|
+
Bisect.insort(a, 3)
|
23
|
+
a == [1, 2, 3, 4]
|
24
|
+
```
|
25
|
+
|
26
|
+
`Bisect.bisect` gives you the index at which the element would have been inserted:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'bisect'
|
30
|
+
a = ['a', 'b', 'd']
|
31
|
+
Bisect.bisect(a, 'c') == 2
|
32
|
+
```
|
33
|
+
|
34
|
+
If there are equal elements in the Array then `insort` will insert the element after the last equal element. Similarly `bisect` will return the index one higher than the last equal element. If you'd like to add new elements before equal elements, use `insort_left` and `bisect_left`. If you need to be explicit then `insort_right` and `bisect_right` are aliases for `insort` and `bisect`.
|
35
|
+
|
36
|
+
Core ext
|
37
|
+
========
|
38
|
+
If you want these methods in your Arrays by default, `require 'bisect/core_ext'` If you're using bundler, add `gem 'bisect', :require => 'bisect/core_ext'` to your Gemfile.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
require 'bisect/core_ext'
|
42
|
+
a = [1, 2, 4]
|
43
|
+
a.insort(3)
|
44
|
+
a == [1, 2, 3, 4]
|
45
|
+
```
|
46
|
+
|
47
|
+
Why?
|
48
|
+
====
|
49
|
+
|
50
|
+
The problem of maintaining a sorted array keeps cropping up, and I like the Python API. As this kind of code has lots of edge-cases, I'm glad the Pythonistas have debugged it already.
|
51
|
+
|
52
|
+
Future work
|
53
|
+
===========
|
54
|
+
|
55
|
+
* Add a subclass of Array that magically stays sorted.
|
56
|
+
|
57
|
+
Meta-fu
|
58
|
+
=======
|
59
|
+
|
60
|
+
Licensed under the MIT license, bug reports and pull requests welcome.
|
data/bisect.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'bisect'
|
3
|
+
gem.version = '0.1'
|
4
|
+
|
5
|
+
gem.summary = 'Library for maintaining sorted arrays'
|
6
|
+
gem.description = "A direct port of python's 'bisect' standard library to ruby."
|
7
|
+
|
8
|
+
gem.authors = ['Conrad Irwin']
|
9
|
+
gem.email = %w(conrad.irwin@gmail.com)
|
10
|
+
gem.homepage = 'http://github.com/ConradIrwin/bisect'
|
11
|
+
|
12
|
+
gem.license = 'MIT'
|
13
|
+
|
14
|
+
gem.required_ruby_version = '>= 1.8.7'
|
15
|
+
|
16
|
+
gem.add_development_dependency 'rspec'
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split("\n")
|
19
|
+
end
|
data/lib/bisect.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# A direct port of the Python bisect standard library.
|
2
|
+
#
|
3
|
+
# http://svn.python.org/view/python/branches/py3k/Lib/bisect.py?view=markup&pathrev=70846
|
4
|
+
#
|
5
|
+
module Bisect
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# Insert item x in list a, and keep it sorted assuming a is sorted.
|
9
|
+
#
|
10
|
+
# If x is already in a, insert it to the right of the rightmost x.
|
11
|
+
#
|
12
|
+
# Optional args lo (default 0) and hi (default len(a)) bound the
|
13
|
+
# slice of a to be searched.
|
14
|
+
def insort_right(a, x, lo=0, hi=a.size)
|
15
|
+
index = bisect_right(a, x, lo, hi)
|
16
|
+
a.insert(index, x)
|
17
|
+
end
|
18
|
+
alias_method :insort, :insort_right
|
19
|
+
|
20
|
+
# Return the index where to insert item x in list a, assuming a is sorted.
|
21
|
+
#
|
22
|
+
# The return value i is such that all e in a[:i] have e <= x, and all e in
|
23
|
+
# a[i:] have e > x. So if x already appears in the list, a.insert(x) will
|
24
|
+
# insert just after the rightmost x already there.
|
25
|
+
#
|
26
|
+
# Optional args lo (default 0) and hi (default len(a)) bound the
|
27
|
+
# slice of a to be searched.
|
28
|
+
def bisect_right(a, x, lo=0, hi=a.size)
|
29
|
+
raise ArgumentError, "lo must be non-negative" if lo < 0
|
30
|
+
|
31
|
+
while lo < hi
|
32
|
+
mid = (lo + hi) / 2
|
33
|
+
if x < a[mid]
|
34
|
+
hi = mid
|
35
|
+
else
|
36
|
+
lo = mid + 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
lo
|
41
|
+
end
|
42
|
+
alias_method :bisect, :bisect_right
|
43
|
+
|
44
|
+
# Insert item x in list a, and keep it sorted assuming a is sorted.
|
45
|
+
#
|
46
|
+
# If x is already in a, insert it to the left of the leftmost x.
|
47
|
+
#
|
48
|
+
# Optional args lo (default 0) and hi (default len(a)) bound the
|
49
|
+
# slice of a to be searched.
|
50
|
+
def insort_left(a, x, lo=0, hi=a.size)
|
51
|
+
index = bisect_left(a, x, lo, hi)
|
52
|
+
a.insert(index, x)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return the index where to insert item x in list a, assuming a is sorted.
|
56
|
+
#
|
57
|
+
# The return value i is such that all e in a[:i] have e < x, and all e in
|
58
|
+
# a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
|
59
|
+
# insert just before the leftmost x already there.
|
60
|
+
#
|
61
|
+
# Optional args lo (default 0) and hi (default len(a)) bound the
|
62
|
+
# slice of a to be searched.
|
63
|
+
def bisect_left(a, x, lo=0, hi=a.size)
|
64
|
+
raise ArgumentError, "lo must be non-negative" if lo < 0
|
65
|
+
|
66
|
+
while lo < hi
|
67
|
+
mid = (lo + hi) / 2
|
68
|
+
if a[mid] < x
|
69
|
+
lo = mid + 1
|
70
|
+
else
|
71
|
+
hi = mid
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
lo
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/bisect_spec.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# http://svn.python.org/view/python/branches/py3k/Lib/test/test_bisect.py?view=markup&pathrev=70846
|
2
|
+
|
3
|
+
describe Bisect do
|
4
|
+
before do
|
5
|
+
@test_cases = [
|
6
|
+
[:right, [], 1, 0],
|
7
|
+
[:right, [1], 0, 0],
|
8
|
+
[:right, [1], 1, 1],
|
9
|
+
[:right, [1], 2, 1],
|
10
|
+
[:right, [1, 1], 0, 0],
|
11
|
+
[:right, [1, 1], 1, 2],
|
12
|
+
[:right, [1, 1], 2, 2],
|
13
|
+
[:right, [1, 1, 1], 0, 0],
|
14
|
+
[:right, [1, 1, 1], 1, 3],
|
15
|
+
[:right, [1, 1, 1], 2, 3],
|
16
|
+
[:right, [1, 1, 1, 1], 0, 0],
|
17
|
+
[:right, [1, 1, 1, 1], 1, 4],
|
18
|
+
[:right, [1, 1, 1, 1], 2, 4],
|
19
|
+
[:right, [1, 2], 0, 0],
|
20
|
+
[:right, [1, 2], 1, 1],
|
21
|
+
[:right, [1, 2], 1.5, 1],
|
22
|
+
[:right, [1, 2], 2, 2],
|
23
|
+
[:right, [1, 2], 3, 2],
|
24
|
+
[:right, [1, 1, 2, 2], 0, 0],
|
25
|
+
[:right, [1, 1, 2, 2], 1, 2],
|
26
|
+
[:right, [1, 1, 2, 2], 1.5, 2],
|
27
|
+
[:right, [1, 1, 2, 2], 2, 4],
|
28
|
+
[:right, [1, 1, 2, 2], 3, 4],
|
29
|
+
[:right, [1, 2, 3], 0, 0],
|
30
|
+
[:right, [1, 2, 3], 1, 1],
|
31
|
+
[:right, [1, 2, 3], 1.5, 1],
|
32
|
+
[:right, [1, 2, 3], 2, 2],
|
33
|
+
[:right, [1, 2, 3], 2.5, 2],
|
34
|
+
[:right, [1, 2, 3], 3, 3],
|
35
|
+
[:right, [1, 2, 3], 4, 3],
|
36
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0],
|
37
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 1],
|
38
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1],
|
39
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 3],
|
40
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3],
|
41
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 6],
|
42
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6],
|
43
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 10],
|
44
|
+
[:right, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10],
|
45
|
+
|
46
|
+
[:left, [], 1, 0],
|
47
|
+
[:left, [1], 0, 0],
|
48
|
+
[:left, [1], 1, 0],
|
49
|
+
[:left, [1], 2, 1],
|
50
|
+
[:left, [1, 1], 0, 0],
|
51
|
+
[:left, [1, 1], 1, 0],
|
52
|
+
[:left, [1, 1], 2, 2],
|
53
|
+
[:left, [1, 1, 1], 0, 0],
|
54
|
+
[:left, [1, 1, 1], 1, 0],
|
55
|
+
[:left, [1, 1, 1], 2, 3],
|
56
|
+
[:left, [1, 1, 1, 1], 0, 0],
|
57
|
+
[:left, [1, 1, 1, 1], 1, 0],
|
58
|
+
[:left, [1, 1, 1, 1], 2, 4],
|
59
|
+
[:left, [1, 2], 0, 0],
|
60
|
+
[:left, [1, 2], 1, 0],
|
61
|
+
[:left, [1, 2], 1.5, 1],
|
62
|
+
[:left, [1, 2], 2, 1],
|
63
|
+
[:left, [1, 2], 3, 2],
|
64
|
+
[:left, [1, 1, 2, 2], 0, 0],
|
65
|
+
[:left, [1, 1, 2, 2], 1, 0],
|
66
|
+
[:left, [1, 1, 2, 2], 1.5, 2],
|
67
|
+
[:left, [1, 1, 2, 2], 2, 2],
|
68
|
+
[:left, [1, 1, 2, 2], 3, 4],
|
69
|
+
[:left, [1, 2, 3], 0, 0],
|
70
|
+
[:left, [1, 2, 3], 1, 0],
|
71
|
+
[:left, [1, 2, 3], 1.5, 1],
|
72
|
+
[:left, [1, 2, 3], 2, 1],
|
73
|
+
[:left, [1, 2, 3], 2.5, 2],
|
74
|
+
[:left, [1, 2, 3], 3, 2],
|
75
|
+
[:left, [1, 2, 3], 4, 3],
|
76
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 0, 0],
|
77
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1, 0],
|
78
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 1.5, 1],
|
79
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2, 1],
|
80
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 2.5, 3],
|
81
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3, 3],
|
82
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 3.5, 6],
|
83
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 4, 6],
|
84
|
+
[:left, [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], 5, 10]
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should bisect like the Python one" do
|
89
|
+
|
90
|
+
@test_cases.each do |direction, array, element, result|
|
91
|
+
case direction
|
92
|
+
when :left
|
93
|
+
Bisect.bisect_left(array, element).should == result
|
94
|
+
when :right
|
95
|
+
Bisect.bisect_right(array, element).should == result
|
96
|
+
else
|
97
|
+
raise "wtf?!"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should insort like the Python one" do
|
104
|
+
array = []
|
105
|
+
500.times do
|
106
|
+
digit = rand(10)
|
107
|
+
if digit % 2 == 0
|
108
|
+
Bisect.insort_left(array, digit)
|
109
|
+
else
|
110
|
+
Bisect.insort_right(array, digit)
|
111
|
+
end
|
112
|
+
array.should == array.sort
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bisect
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Conrad Irwin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A direct port of python's 'bisect' standard library to ruby.
|
31
|
+
email:
|
32
|
+
- conrad.irwin@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .rspec
|
38
|
+
- LICENSE.MIT
|
39
|
+
- README.md
|
40
|
+
- bisect.gemspec
|
41
|
+
- lib/bisect.rb
|
42
|
+
- lib/bisect/core_ext.rb
|
43
|
+
- spec/bisect_spec.rb
|
44
|
+
homepage: http://github.com/ConradIrwin/bisect
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.8.7
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.23
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Library for maintaining sorted arrays
|
69
|
+
test_files: []
|
70
|
+
has_rdoc:
|