Cartesian 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cartesian.rb CHANGED
@@ -30,16 +30,18 @@
30
30
  # bar = ["a", "b"]
31
31
  # foo.cartesian(bar) #=> [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
32
32
 
33
+ require 'cartesian_iterator'
34
+
33
35
  module Cartesian
34
36
 
35
37
  # Produces the cartesian product of self and other.
36
38
  # The result is an array of pairs (i.e. two-element arrays).
37
39
  #
38
- # cartesian( [1,2], %w(A B) ) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
40
+ # Cartesian::product( [1,2], %w(A B) ) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
39
41
  #
40
42
  # or, if mixed in into Array,
41
43
  #
42
- # [1,2].cartesian %w(A B) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
44
+ # [1,2].cartesian %w(A B) #=> [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
43
45
  #
44
46
  def Cartesian.product(first, second)
45
47
  result = []
@@ -59,11 +61,11 @@ module Cartesian
59
61
 
60
62
  # Behaves as product, except for the elements are joined.
61
63
  #
62
- # joined_cartesian( [1,2], %w(A B) ) #=> ["1A", "1B", "2A", "2B"]
64
+ # Cartesian::joined_cartesian( [1,2], %w(A B) ) #=> ["1A", "1B", "2A", "2B"]
63
65
  #
64
66
  # or, if mixed in into Array,
65
67
  #
66
- # [1,2].joined_cartesian %w(A B) #=> ["1A", "1B", "2A", "2B"]
68
+ # [1,2].joined_cartesian %w(A B) #=> ["1A", "1B", "2A", "2B"]
67
69
  #
68
70
  def Cartesian.joined_product(first, second)
69
71
  product(first, second).map {|pair| pair.join }
@@ -74,8 +76,42 @@ module Cartesian
74
76
  def joined_cartesian(other)
75
77
  Cartesian.joined_product(self, other)
76
78
  end
79
+
80
+ # Convenient way of iterating over the elements.
81
+ # Preferable when the cartesian product array
82
+ # is not needed, for the consumption of memory
83
+ # is fixed and very small, in contrast with the
84
+ # exponential memory requirements of the
85
+ # conventional approach.
86
+ #
87
+ # for row, col in (1..10).x(1..30)
88
+ # Matrix[row, col] = row**2 + col**3
89
+ # end
90
+ #
91
+ # Of course, calls can be chained as in
92
+ #
93
+ # for x, y, z in (1..10).x(1..10).x(1..10)
94
+ # # ... do something ...
95
+ # end
96
+ #
97
+ #--
98
+ # for letter, number in %w{a b c}.x(1..3)
99
+ # ... do something ...
100
+ # end
101
+ #
102
+ #++
103
+ # Beware that both +self+ and +other+ must implement
104
+ # +to_a+, i.e., be convertible to array.
105
+ #
106
+ def x(other)
107
+ CartesianIterator.new(self, other)
108
+ end
77
109
  end
78
110
 
79
111
  class Array
80
112
  include Cartesian
81
113
  end
114
+
115
+ class Range
116
+ include Cartesian
117
+ end
@@ -0,0 +1,70 @@
1
+ class CartesianIterator
2
+ def initialize(foo, bar)
3
+ @lists = []
4
+ @tot_iter = 1
5
+ x(foo)
6
+ x(bar)
7
+ end
8
+
9
+ def x(other)
10
+ @lists << other.to_a
11
+ @tot_iter *= @lists[-1].size
12
+ self
13
+ end
14
+
15
+ def each
16
+ return false if @tot_iter < 1
17
+
18
+ elems = []
19
+ for list in @lists
20
+ elems << list.restart_and_raw_next
21
+ end
22
+ yield *elems
23
+
24
+ last_list_index = @lists.size-1
25
+ n = last_list_index
26
+ loop do
27
+ if elems[n] = @lists[n].raw_next
28
+ yield *elems
29
+ n = last_list_index
30
+ next
31
+ elsif n > 0
32
+ elems[n] = @lists[n].restart_and_raw_next
33
+ n -= 1
34
+ else
35
+ return true
36
+ end
37
+ end
38
+ end
39
+
40
+ def to_a
41
+ array = []
42
+ self.each {|*element| array << element }
43
+ array
44
+ end
45
+ end
46
+
47
+ module Iterable
48
+ def start
49
+ @next_index = -1
50
+ true
51
+ end
52
+ alias :restart :start
53
+
54
+ def next
55
+ @next_index or restart
56
+ raw_next
57
+ end
58
+
59
+ def raw_next
60
+ self[@next_index += 1]
61
+ end
62
+
63
+ def restart_and_raw_next
64
+ self[@next_index = 0]
65
+ end
66
+ end
67
+
68
+ class Array
69
+ include Iterable
70
+ end
data/tests/benchmark.rb CHANGED
@@ -1,4 +1,4 @@
1
- require '../lib/cartesian'
1
+ require 'cartesian'
2
2
  require 'benchmark'
3
3
 
4
4
  MULTIPLIER = 3
@@ -6,11 +6,15 @@ letras = ("a"*MULTIPLIER.."z"*MULTIPLIER).to_a
6
6
  numeros = (0..10**1).to_a
7
7
 
8
8
  Benchmark.bmbm do |x|
9
- x.report("product") { Cartesian.product(letras, numeros) }
10
- x.report("productZip") { Cartesian.productZip(letras, numeros) }
11
- end
9
+ letras_numeros = nil
10
+ x.report("product") { letras_numeros = Cartesian.product(letras, numeros) }
11
+ x.report("product 2") { for x,y in letras_numeros; end }
12
12
 
13
+ x.report(".x") { letras_numeros = letras.x(numeros) }
14
+ x.report(".x 2") { for x,y in letras_numeros; end }
15
+ end
13
16
 
17
+ #~ x.report("productZip") { Cartesian.productZip(letras, numeros) }
14
18
 
15
19
  #~ def Cartesian.productZip(first, second)
16
20
  #~ result = []
@@ -20,4 +24,3 @@ end
20
24
  #~ end
21
25
  #~ result
22
26
  #~ end
23
-
@@ -1,23 +1,30 @@
1
- require '../lib/cartesian'
2
- require 'benchmark'
1
+ require 'test/unit'
3
2
 
4
- MULTIPLIER = 3
5
- letras = ("a"*MULTIPLIER.."z"*MULTIPLIER).to_a
6
- numeros = (0..10**1).to_a
7
-
8
- Benchmark.bmbm do |x|
9
- x.report("product") { Cartesian.product(letras, numeros) }
10
- x.report("productZip") { Cartesian.productZip(letras, numeros) }
11
- end
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4
+ require 'cartesian'
12
5
 
6
+ class TestCartesian < Test::Unit::TestCase
7
+ def test_arrays
8
+ foo = [1,2,3]
9
+ bar = %w{a b c}
10
+ expected = [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"],
11
+ [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
12
+ assert(foo.x(bar).to_a == expected)
13
+ end
13
14
 
15
+ def test_ranges
16
+ foo = 1..3
17
+ bar = 4..6
18
+ expected = [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5],
19
+ [2, 6], [3, 4], [3, 5], [3, 6]]
20
+ assert(foo.x(bar).to_a == expected)
21
+ end
14
22
 
15
- #~ def Cartesian.productZip(first, second)
16
- #~ result = []
17
- #~ first.each do |a|
18
- #~ aaa = Array.new(second.size) { a }
19
- #~ result += aaa.zip(second)
20
- #~ end
21
- #~ result
22
- #~ end
23
-
23
+ def test_mixed
24
+ foo = 1..3
25
+ bar = %w{a b c}
26
+ expected = [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"],
27
+ [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
28
+ assert(foo.x(bar).to_a == expected)
29
+ end
30
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: Cartesian
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-11-24 00:00:00 -03:00
6
+ version: 0.2.1
7
+ date: 2007-01-07 00:00:00 -03:00
8
8
  summary: The Cartesian module provide methods for the calculation of the cartesian producted between two enumberable objects. It can also be easily mixed in into any enumberable class, i.e. any class with Enumerable module mixed in.
9
9
  require_paths:
10
10
  - lib
@@ -32,6 +32,7 @@ files:
32
32
  - tests/benchmark.rb
33
33
  - tests/tc_cartesian.rb
34
34
  - lib/cartesian.rb
35
+ - lib/cartesian_iterator.rb
35
36
  test_files:
36
37
  - tests/tc_cartesian.rb
37
38
  rdoc_options: []