cartesian-product 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "rspec", "~> 2.3.0"
5
+ gem "bundler", "~> 1.0.0"
6
+ gem "jeweler", "~> 1.6.4"
7
+ end
@@ -0,0 +1,26 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.9.2.2)
11
+ rspec (2.3.0)
12
+ rspec-core (~> 2.3.0)
13
+ rspec-expectations (~> 2.3.0)
14
+ rspec-mocks (~> 2.3.0)
15
+ rspec-core (2.3.1)
16
+ rspec-expectations (2.3.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.3.0)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (~> 1.0.0)
25
+ jeweler (~> 1.6.4)
26
+ rspec (~> 2.3.0)
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Art.sy, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ 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 THE
19
+ SOFTWARE.
@@ -0,0 +1,49 @@
1
+ cartesian-product
2
+ =================
3
+
4
+ Ruby's Enumerable.product materializes the entire cartesian product
5
+ of a sequence of arrays into an array of arrays, so a call like:
6
+
7
+ [(0..100).to_a, (0..100).to_a, (0..100).to_a].reduce(&:product).map(&:flatten)
8
+
9
+ actually returns an array of a million elements. This module implements
10
+ an iterator over the cartesian product of an arbitrary number of arrays,
11
+ allowing you to start and stop at a particular index in the lexicographic
12
+ ordering without ever representing the cartesian product in memory.
13
+
14
+ Quick examples:
15
+ ===============
16
+
17
+ >> prod = CartesianProduct.new([1,2], [100,101], ['a','b'])
18
+ >> prod.each { |element| puts element }
19
+
20
+ [1, 100, 'a']
21
+ [1, 100, 'b']
22
+ [1, 101, 'a']
23
+ [1, 101, 'b']
24
+ [2, 100, 'a']
25
+ [2, 100, 'b']
26
+ [2, 101, 'a']
27
+ [2, 101, 'b']
28
+
29
+ >> prod.each(0, 2) { |element| puts element }
30
+
31
+ [1, 100, 'a']
32
+ [1, 100, 'b']
33
+
34
+ >> prod.each(4, 7) { |element| puts element }
35
+
36
+ [2, 100, 'a']
37
+ [2, 100, 'b']
38
+ [2, 101, 'a']
39
+
40
+ >> prod.each(-3, -1) { |element| puts element }
41
+
42
+ [2, 100, 'b']
43
+ [2, 101, 'a']
44
+ [2, 101, 'b']
45
+
46
+ Installation
47
+ ============
48
+
49
+ gem install cartesian-product
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "cartesian-product"
18
+ gem.homepage = "http://github.com/aaw/cartesian-product"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A cartesian product implementation in Ruby that doesn't hold the full product in memory}
21
+ gem.description = %Q{A cartesian product implementation in Ruby that doesn't hold the full product in memory}
22
+ gem.email = "aaron.windsor@gmail.com"
23
+ gem.authors = ["Aaron Windsor"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ task :default => :spec
35
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,29 @@
1
+ class CartesianProduct
2
+ include Enumerable
3
+
4
+ def initialize(*arrays)
5
+ @arrays = arrays.reverse
6
+ @num_elements = @arrays.inject(1){ |accum, item| accum *= item.length }
7
+ end
8
+
9
+ def count
10
+ @num_elements
11
+ end
12
+
13
+ def each(start_index=0, stop_index=-1)
14
+ start_index = @num_elements + start_index if start_index < 0
15
+ stop_index = @num_elements + stop_index + 1 if stop_index < 0
16
+ (start_index...stop_index).each { |index| yield(index_to_item(index)) }
17
+ end
18
+
19
+ protected
20
+
21
+ def index_to_item(index)
22
+ @arrays.map do |array|
23
+ element = array[index % array.length]
24
+ index /= array.length
25
+ element
26
+ end.reverse
27
+ end
28
+
29
+ end
@@ -0,0 +1,59 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "CartesianProduct" do
4
+ it "behaves correctly when given an empty list" do
5
+ CartesianProduct.new.to_a.should == [[]]
6
+ end
7
+ it "correctly computes the product of single array" do
8
+ CartesianProduct.new([1,2,3]).to_a.should == [[1],[2],[3]]
9
+ end
10
+ it "correctly computes the product of two arrays" do
11
+ CartesianProduct.new([1,2,3],['a','b']).to_a.should == [1,2,3].product(['a','b'])
12
+ end
13
+ it "correctly computes the product of three arrays" do
14
+ CartesianProduct.new([1,2], ['a','b','c'], [:d]).to_a.should == [[1,2], ['a','b','c'], [:d]].reduce(&:product).map(&:flatten)
15
+ end
16
+ it "handles an empty array mixed with non-empty arrays correctly" do
17
+ CartesianProduct.new([1,2], ['a','b','c'], []).to_a.should == [[1,2], ['a','b','c'], []].reduce(&:product).map(&:flatten)
18
+ end
19
+ it "allows iteration over arbitrary ranges" do
20
+ prod = CartesianProduct.new([1,2,3], [:four, :five, :size], ['seven', 'eight', 'nine'])
21
+ collection = []
22
+ prod.each(0, 2) { |x| collection << x }
23
+ prod.each(2, 7) { |x| collection << x }
24
+ prod.each(7, prod.count) { |x| collection << x }
25
+ prod.to_a.should == collection
26
+ end
27
+ it "returns the count of elements in the product" do
28
+ prod = CartesianProduct.new([1,2,3], [:four], ['five', 'six'])
29
+ prod.count.should == [1,2,3].length * [:four].length * ['five','six'].length
30
+ end
31
+ it "allows indexing using negative numbers" do
32
+ prod = CartesianProduct.new([1,2,3], [:four], ['five', 'six'])
33
+ items = []
34
+ prod.each(0,-1) { |x| items << x }
35
+ prod.to_a.should == items
36
+
37
+ items = []
38
+ prod.each(0,-2) { |x| items << x }
39
+ prod.to_a[0..-2].should == items
40
+
41
+ items = []
42
+ prod.each(-5, -3) { |x| items << x }
43
+ prod.to_a[-5..-3].should == items
44
+ end
45
+ it "allows iterating over the same range multiple times" do
46
+ prod = CartesianProduct.new((0..1000).to_a, (0..1000).to_a, (0..1000).to_a)
47
+ items_1 = []
48
+ prod.each(60, 67) { |x| items_1 << x }
49
+ items_2 = []
50
+ prod.each(60, 67) { |x| items_2 << x }
51
+ items_1.should == items_2
52
+ end
53
+ it "iterates over the array without materializing it" do
54
+ results = []
55
+ CartesianProduct.new((0..1000).to_a, (0..1000).to_a, (0..1000).to_a).each(9000,9002) { |x| results << x }
56
+ results.length.should == 2
57
+ results.each{ |result| result.length.should == 3 }
58
+ end
59
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'cartesian-product'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cartesian-product
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aaron Windsor
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-18 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2168207780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.3.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2168207780
25
+ - !ruby/object:Gem::Dependency
26
+ name: bundler
27
+ requirement: &2168207160 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2168207160
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &2168206480 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.6.4
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2168206480
47
+ description: A cartesian product implementation in Ruby that doesn't hold the full
48
+ product in memory
49
+ email: aaron.windsor@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - LICENSE.txt
54
+ - README.md
55
+ files:
56
+ - .rspec
57
+ - Gemfile
58
+ - Gemfile.lock
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - VERSION
63
+ - lib/cartesian-product.rb
64
+ - spec/cartesian-product_spec.rb
65
+ - spec/spec_helper.rb
66
+ homepage: http://github.com/aaw/cartesian-product
67
+ licenses:
68
+ - MIT
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ segments:
80
+ - 0
81
+ hash: 4597596894606092724
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.10
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: A cartesian product implementation in Ruby that doesn't hold the full product
94
+ in memory
95
+ test_files: []