bisect 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -r./lib/bisect/core_ext
@@ -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.
@@ -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.
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'bisect'
2
+ class Array
3
+ # Copy all methods from Bisect onto all arrays.
4
+ Bisect.methods(false).each do |method|
5
+ define_method(method) do |*args|
6
+ Bisect.send(method, self, *args)
7
+ end
8
+ end
9
+ end
@@ -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: