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 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: