huge_enumerable 0.0.1 → 0.0.2

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.
@@ -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