huge_enumerable 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,83 +1,83 @@
1
- require 'huge_enumerable'
2
- # The simplest form of a HugeEnumerable.
3
- # This class can be used for large arrays or anything else that responds to [].
4
- # It is not necessary for the enumerable to be completely mapped into memory.
5
- # It only has to be able to return the element mapped to the index given to [].
6
- # ==== Examples
7
- #
8
- # Using HugeCollection directly:
9
- #
10
- # original_array = ('a'..'z').to_a
11
- # collection = HugeCollection.new(original_array)
12
- # collection.shuffle!
13
- # original_array[0..4] # => ["a", "b", "c", "d", "e"]
14
- # collection[0..4] # => ["j", "a", "r", "i", "z"]
15
- #
16
- #
17
- # Subclassing HugeCollection
18
- #
19
- # class StringNext < HugeCollection
20
- #
21
- # def initialize(size)
22
- # @collection_size = size
23
- # super ('a'..'z').to_a
24
- # end
25
- #
26
- # private
27
- #
28
- # def fetch(index)
29
- # result = ""
30
- # index += 1
31
- # while index > 0
32
- # index -= 1
33
- # result.prepend super(index % 26)
34
- # index /= 26
35
- # end
36
- # result
37
- # end
38
- #
39
- # end
40
- #
41
- # googol = 10*100
42
- # collection = StringNext.new(googol)
43
- # collection.size # => 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
44
- # collection[0] # => "a"
45
- # collection[-1] # => "zhxrtplbmwaiwcqlzpmglpziaegsdivmbvlnssusbjtbcgywaycqnhxztqwwikxvrsptazpp"
46
- # collection[googol / 2] # => "dlijhfafxmqxnusmhfpshmdmopvodxfnkfgivwvnejaapyxmynutdlmjhxxqrykiiuizzhi"
47
- # collection.shuffle!
48
- # collection[0] # => "bipzqqzayczkgsmaseflwktpsotzclcjsqlnnjaciaawufpojywxflknuddhqkilhoedacn"
49
- # collecyion[-1] # => "etneuebyurxgrvrfsreesxuvjaiyoqwplofsptacjdbhuhafdiwbwujvniokltgkjbfkiuy"
50
- class HugeCollection < HugeEnumerable
51
-
52
- # Create a new HugeCollection
53
- #
54
- # ==== Attributes
55
- #
56
- # * +enumerable+ - Any enumerable that responds to []
57
- #
58
- # ==== Options
59
- #
60
- # * +:max_array_size+ - The default size of arrays when #to_a is called.
61
- # * +:rng+ - The random number generator to use.
62
- def initialize(enumerable, max_array_size = nil, rng = nil)
63
- @enum = enumerable
64
- super(max_array_size, rng)
65
- end
66
-
67
- private
68
-
69
- attr_accessor :enum
70
-
71
- def collection_size
72
- @collection_size ||= enum_size
73
- end
74
-
75
- def enum_size
76
- @enum_size ||= enum.size
77
- end
78
-
79
- def fetch(index)
80
- enum[index]
81
- end
82
-
83
- end
1
+ require 'huge_enumerable'
2
+ # The simplest form of a HugeEnumerable.
3
+ # This class can be used for large arrays or anything else that responds to [].
4
+ # It is not necessary for the enumerable to be completely mapped into memory.
5
+ # It only has to be able to return the element mapped to the index given to [].
6
+ # ==== Examples
7
+ #
8
+ # Using HugeCollection directly:
9
+ #
10
+ # original_array = ('a'..'z').to_a
11
+ # collection = HugeCollection.new(original_array)
12
+ # collection.shuffle!
13
+ # original_array[0..4] # => ["a", "b", "c", "d", "e"]
14
+ # collection[0..4] # => ["j", "a", "r", "i", "z"]
15
+ #
16
+ #
17
+ # Subclassing HugeCollection
18
+ #
19
+ # class StringNext < HugeCollection
20
+ #
21
+ # def initialize(size)
22
+ # @collection_size = size
23
+ # super ('a'..'z').to_a
24
+ # end
25
+ #
26
+ # private
27
+ #
28
+ # def fetch(index)
29
+ # result = ""
30
+ # index += 1
31
+ # while index > 0
32
+ # index -= 1
33
+ # result.prepend super(index % 26)
34
+ # index /= 26
35
+ # end
36
+ # result
37
+ # end
38
+ #
39
+ # end
40
+ #
41
+ # googol = 10*100
42
+ # collection = StringNext.new(googol)
43
+ # collection.size # => 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
44
+ # collection[0] # => "a"
45
+ # collection[-1] # => "zhxrtplbmwaiwcqlzpmglpziaegsdivmbvlnssusbjtbcgywaycqnhxztqwwikxvrsptazpp"
46
+ # collection[googol / 2] # => "dlijhfafxmqxnusmhfpshmdmopvodxfnkfgivwvnejaapyxmynutdlmjhxxqrykiiuizzhi"
47
+ # collection.shuffle!
48
+ # collection[0] # => "bipzqqzayczkgsmaseflwktpsotzclcjsqlnnjaciaawufpojywxflknuddhqkilhoedacn"
49
+ # collection[-1] # => "etneuebyurxgrvrfsreesxuvjaiyoqwplofsptacjdbhuhafdiwbwujvniokltgkjbfkiuy"
50
+ class HugeCollection < HugeEnumerable
51
+
52
+ # Create a new HugeCollection
53
+ #
54
+ # ==== Attributes
55
+ #
56
+ # * +enumerable+ - Any enumerable that responds to []
57
+ #
58
+ # ==== Options
59
+ #
60
+ # * +:max_array_size+ - The default size of arrays when #to_a is called.
61
+ # * +:rng+ - The random number generator to use.
62
+ def initialize(enumerable, max_array_size = nil, rng = nil)
63
+ @enum = enumerable
64
+ super(max_array_size, rng)
65
+ end
66
+
67
+ private
68
+
69
+ attr_accessor :enum
70
+
71
+ def collection_size
72
+ @collection_size ||= enum_size
73
+ end
74
+
75
+ def enum_size
76
+ @enum_size ||= enum.size
77
+ end
78
+
79
+ def fetch(index)
80
+ enum[index]
81
+ end
82
+
83
+ end
@@ -1,118 +1,112 @@
1
- require 'huge_enumerable'
2
- # HugeCombination is a HugeEnumerable style combination. Comparable to Array#combination.
3
- # This class can be used to generate combinations of large arrays or anything else that responds to [].
4
- # It is not necessary for the enumerable to be completely mapped into memory.
5
- # It only has to be able to return the element mapped to the index given to [].
6
- # ==== Examples
7
- #
8
- # Using HugeCombination directly:
9
- #
10
- # combination = HugeCombination.new(('a'..'z').to_a, 2)
11
- # combination[0..4] # => [["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"]]
12
- # combination[23..27] # => [["a", "y"], ["a", "z"], ["b", "c"], ["b", "d"], ["b", "e"]]
13
- #
14
- #
15
- # Subclassing HugeCombination
16
- #
17
- # class NumberArray < HugeCollection
18
- #
19
- # def initialize(size)
20
- # @collection_size = size
21
- # super(nil)
22
- # end
23
- #
24
- # private
25
- #
26
- # def fetch(index)
27
- # index
28
- # end
29
- #
30
- # end
31
- #
32
- # class NumberCombination < HugeCombination
33
- #
34
- # def initialize(size)
35
- # enumerable = size < 10 ? (0...size).to_a : NumberArray.new(size)
36
- # super enumerable, 2, nil, nil
37
- # end
38
- #
39
- # private
40
- #
41
- # def fetch(index)
42
- # array = super
43
- # sum = array.inject(0) { |sum, i| sum += i }
44
- # "#{array.first} + #{array.last} = #{sum}"
45
- # end
46
- #
47
- # end
48
- #
49
- # combination = NumberCombination.new(10**30)
50
- # size = combination.size # => 499999999999999999999999999999500000000000000000000000000000
51
- # combination[0] # => "0 + 1 = 1"
52
- # combination[-1] # => "999999999999999999999999999998 + 999999999999999999999999999999 = 1999999999999999999999999999997"
53
- # combination[size / 2] # => "292893218813452475599155637895 + 296085173605458049080913472356 = 588978392418910524680069110251"
54
- class HugeCombination < HugeCollection
55
-
56
- # Create a new HugeCombination
57
- #
58
- # ==== Attributes
59
- #
60
- # * +enumerable+ - Any enumerable that responds to []
61
- # * +size+ - The number of elements per combination to use from enumerable. (Currently only size 2 is supported)
62
- #
63
- # ==== Options
64
- #
65
- # * +:max_array_size+ - The default size of arrays when #to_a is called.
66
- # * +:rng+ - The random number generator to use.
67
- def initialize(enumerable, size, max_array_size = nil, rng = nil)
68
- raise NotImplementedError, "Not yet implemented for any size != 2" if size != 2 # TODO: Extend this class to handle length N
69
- @combination_size = size
70
- super(enumerable, max_array_size, rng)
71
- end
72
-
73
- private
74
-
75
- def collection_size
76
- sum(enum_size - 1)
77
- end
78
-
79
- def fetch(index)
80
- cycle = locate_cycle(index)
81
- first_index = cycle - 1
82
- max_cycles = enum_size - 1
83
- used = (cycle - 1) == 0 ? 0 : sum_from(max_cycles, max_cycles - (cycle - 2))
84
- second_index = index - used + cycle
85
- [enum[first_index], enum[second_index]]
86
- end
87
-
88
- def locate_cycle(index, min=0, max=enum_size-1)
89
- cycle = min + (max - min) / 2
90
-
91
- check_high = sum_at_cycle(cycle)
92
- check_low = sum_at_cycle(cycle - 1)
93
-
94
- if check_high > index && check_low <= index
95
- cycle
96
- elsif check_low > index
97
- locate_cycle(index, min, cycle-1)
98
- else
99
- locate_cycle(index, cycle+1, max)
100
- end
101
- end
102
-
103
- def sum(x)
104
- x * (x + 1) / 2
105
- end
106
-
107
- def sum_from(m, n)
108
- m, n = [n, m] if m > n
109
- (n + 1 - m)*(n + m)/2
110
- end
111
-
112
- def sum_at_cycle(c)
113
- ec = enum_size * c
114
- (-c + 2*ec - c**2)/2
115
- end
116
-
117
- end
118
-
1
+ require 'huge_enumerable'
2
+ # HugeCombination is a HugeEnumerable style combination. Comparable to Array#combination.
3
+ # This class can be used to generate combinations of large arrays or anything else that responds to [].
4
+ # It is not necessary for the enumerable to be completely mapped into memory.
5
+ # It only has to be able to return the element mapped to the index given to [].
6
+ # ==== Examples
7
+ #
8
+ # Using HugeCombination directly:
9
+ #
10
+ # combination = HugeCombination.new(('a'..'z').to_a, 2)
11
+ # combination[0..4] # => [["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"]]
12
+ # combination[23..27] # => [["a", "y"], ["a", "z"], ["b", "c"], ["b", "d"], ["b", "e"]]
13
+ #
14
+ #
15
+ # Subclassing HugeCombination
16
+ #
17
+ # class NumberArray < HugeCollection
18
+ #
19
+ # def initialize(size)
20
+ # @collection_size = size
21
+ # super(nil)
22
+ # end
23
+ #
24
+ # private
25
+ #
26
+ # def fetch(index)
27
+ # index
28
+ # end
29
+ #
30
+ # end
31
+ #
32
+ # class NumberCombination < HugeCombination
33
+ #
34
+ # def initialize(size)
35
+ # enumerable = size < 10 ? (0...size).to_a : NumberArray.new(size)
36
+ # super enumerable, 2, nil, nil
37
+ # end
38
+ #
39
+ # private
40
+ #
41
+ # def fetch(index)
42
+ # array = super
43
+ # sum = array.inject(0) { |sum, i| sum += i }
44
+ # "#{array.first} + #{array.last} = #{sum}"
45
+ # end
46
+ #
47
+ # end
48
+ #
49
+ # combination = NumberCombination.new(10**30)
50
+ # size = combination.size # => 499999999999999999999999999999500000000000000000000000000000
51
+ # combination[0] # => "0 + 1 = 1"
52
+ # combination[-1] # => "999999999999999999999999999998 + 999999999999999999999999999999 = 1999999999999999999999999999997"
53
+ # combination[size / 2] # => "292893218813452475599155637895 + 296085173605458049080913472356 = 588978392418910524680069110251"
54
+ class HugeCombination < HugeCollection
55
+
56
+ # Create a new HugeCombination
57
+ #
58
+ # ==== Attributes
59
+ #
60
+ # * +enumerable+ - Any enumerable that responds to []
61
+ # * +size+ - The number of elements per combination to use from enumerable.
62
+ #
63
+ # ==== Options
64
+ #
65
+ # * +:max_array_size+ - The default size of arrays when #to_a is called.
66
+ # * +:rng+ - The random number generator to use.
67
+ def initialize(enumerable, size, max_array_size = nil, rng = nil)
68
+ @combination_size = size
69
+ super(enumerable, max_array_size, rng)
70
+ end
71
+
72
+ private
73
+
74
+ attr_reader :combination_size
75
+
76
+ def collection_size
77
+ @collection_size ||= size_of_combination(enum_size, combination_size)
78
+ end
79
+
80
+ def fetch(index)
81
+ indexes_for(collection_size - index - 1).map { |i| enum[enum_size - i - 1] }
82
+ end
83
+
84
+ def size_of_combination(n, k)
85
+ k < 0 || n < k ? 0 : factorial(n)/(factorial(k) * factorial(n - k))
86
+ end
87
+
88
+ def indexes_for(position)
89
+ k = combination_size
90
+ indexes = []
91
+ while k > 0
92
+ n, size = next_n_and_size(position, k)
93
+ position -= size
94
+ k -= 1
95
+ indexes << n
96
+ end
97
+ indexes
98
+ end
99
+
100
+ def next_n_and_size(p, k)
101
+ n = k - 1
102
+ size = size_of_combination(n, k)
103
+ begin
104
+ rc = [n, size]
105
+ n += 1
106
+ size = size_of_combination(n, k)
107
+ end while size <= p
108
+ rc
109
+ end
110
+
111
+ end
112
+
@@ -1,67 +1,80 @@
1
- require 'huge_enumerable'
2
- # HugePermutation is a HugeEnumerable style permutation. Comparable to Array#permutation.
3
- # This class can be used to generate permutations of large arrays or anything else that responds to [].
4
- # It is not necessary for the enumerable to be completely mapped into memory.
5
- # It only has to be able to return the element mapped to the index given to [].
6
- # ==== Examples
7
- #
8
- # Using HugePermutation directly:
9
- #
10
- # permutation = HugePermutation.new(('a'..'z').to_a, 2)
11
- # permutation[0..4] # => [["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"]]
12
- # permutation[23..27] # => [["a", "y"], ["a", "z"], ["b", "a"], ["b", "c"], ["b", "d"]]
13
- #
14
- #
15
- # Subclassing HugePermutation
16
- #
17
- # class SouthernNames < HugePermutation
18
- #
19
- # def initialize
20
- # base_names = %w{Bill Joe Jo Bob Mary Lou Betty Sue Jimmy Ann Lee Ruby Jack Belle Daisy Dixie Lynn}
21
- # super base_names, 2, nil, nil
22
- # end
23
- #
24
- # private
25
- #
26
- # def fetch(index)
27
- # "Your southern name is: #{super(index).join(' ')}"
28
- # end
29
- #
30
- # end
31
- #
32
- # southern_name = SouthernNames.new
33
- # southern_name[0] # => "Your southern name is: Bill Joe"
34
- # southern_name[-1] # => "Your southern name is: Lynn Dixie"
35
- # size = southern_name.size # => 272
36
- # southern_name[size / 2] # => "Your southern name is: Jimmy Ann"
37
- class HugePermutation < HugeCollection
38
-
39
- # Create a new HugePermutation
40
- #
41
- # ==== Attributes
42
- #
43
- # * +enumerable+ - Any enumerable that responds to []
44
- # * +size+ - The number of elements per permutation to use from enumerable. (Currently only size 2 is supported)
45
- #
46
- # ==== Options
47
- #
48
- # * +:max_array_size+ - The default size of arrays when #to_a is called.
49
- # * +:rng+ - The random number generator to use.
50
- def initialize(enumerable, length, max_array_size = nil, rng = nil)
51
- raise NotImplementedError, "Not yet implemented for any length != 2" if length != 2 # TODO: Extend this class to handle length N
52
- super(enumerable, max_array_size, rng)
53
- end
54
-
55
- private
56
-
57
- def fetch(x)
58
- first_index = x / (enum_size - 1)
59
- second_index = ((x % enum_size) + (x / enum_size + 1)) % enum_size
60
- [enum[first_index], enum[second_index]]
61
- end
62
-
63
- def collection_size
64
- enum_size * (enum_size - 1)
65
- end
66
-
67
- end
1
+ require 'huge_enumerable'
2
+ # HugePermutation is a HugeEnumerable style permutation. Comparable to Array#permutation.
3
+ # This class can be used to generate permutations of large arrays or anything else that responds to [].
4
+ # It is not necessary for the enumerable to be completely mapped into memory.
5
+ # It only has to be able to return the element mapped to the index given to [].
6
+ # ==== Examples
7
+ #
8
+ # Using HugePermutation directly:
9
+ #
10
+ # permutation = HugePermutation.new(('a'..'z').to_a, 2)
11
+ # permutation[0..4] # => [["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"]]
12
+ # permutation[23..27] # => [["a", "y"], ["a", "z"], ["b", "a"], ["b", "c"], ["b", "d"]]
13
+ #
14
+ #
15
+ # Subclassing HugePermutation
16
+ #
17
+ # class SouthernNames < HugePermutation
18
+ #
19
+ # def initialize
20
+ # base_names = %w{Bill Joe Jo Bob Mary Lou Betty Sue Jimmy Ann Lee Ruby Jack Belle Daisy Dixie Lynn}
21
+ # super base_names, 2, nil, nil
22
+ # end
23
+ #
24
+ # private
25
+ #
26
+ # def fetch(index)
27
+ # "Your southern name is: #{super(index).join(' ')}"
28
+ # end
29
+ #
30
+ # end
31
+ #
32
+ # southern_name = SouthernNames.new
33
+ # southern_name[0] # => "Your southern name is: Bill Joe"
34
+ # southern_name[-1] # => "Your southern name is: Lynn Dixie"
35
+ # size = southern_name.size # => 272
36
+ # southern_name[size / 2] # => "Your southern name is: Jimmy Ann"
37
+ class HugePermutation < HugeCollection
38
+
39
+ # Create a new HugePermutation
40
+ #
41
+ # ==== Attributes
42
+ #
43
+ # * +enumerable+ - Any enumerable that responds to []
44
+ # * +size+ - The number of elements per permutation to use from enumerable.
45
+ #
46
+ # ==== Options
47
+ #
48
+ # * +:max_array_size+ - The default size of arrays when #to_a is called.
49
+ # * +:rng+ - The random number generator to use.
50
+ def initialize(enumerable, size, max_array_size = nil, rng = nil)
51
+ @permutation_size = size
52
+ super(enumerable, max_array_size, rng)
53
+ end
54
+
55
+ private
56
+
57
+ attr_accessor :permutation_size
58
+
59
+ def fetch(x)
60
+ indexes_for(x).map { |i| enum[i] }
61
+ end
62
+
63
+ def collection_size
64
+ @collection_size ||= factorial(enum_size) / factorial(enum_size - permutation_size)
65
+ end
66
+
67
+ def indexes_for(position)
68
+ inversions = []
69
+ (enum_size-permutation_size+1..enum_size).each do |m|
70
+ inversions.unshift(position % m)
71
+ position /= m
72
+ end
73
+
74
+ indexes = []
75
+ positions = (0..enum_size-1).to_a
76
+ permutation_size.times { |i| indexes << positions.delete_at(inversions[i]) }
77
+ indexes
78
+ end
79
+
80
+ end