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.
- checksums.yaml +7 -0
- data/.gitignore +21 -20
- data/Gemfile +3 -3
- data/LICENSE.txt +22 -22
- data/README.md +29 -29
- data/Rakefile +17 -17
- data/huge_enumerable.gemspec +28 -28
- data/lib/huge_enumerable.rb +362 -357
- data/lib/huge_enumerable/huge_collection.rb +83 -83
- data/lib/huge_enumerable/huge_combination.rb +112 -118
- data/lib/huge_enumerable/huge_permutation.rb +80 -67
- data/lib/huge_enumerable/huge_product.rb +77 -77
- data/lib/huge_enumerable/version.rb +4 -4
- data/spec/lib/huge_enumerable/huge_collection_spec.rb +32 -32
- data/spec/lib/huge_enumerable/huge_combination_spec.rb +38 -37
- data/spec/lib/huge_enumerable/huge_permutation_spec.rb +38 -37
- data/spec/lib/huge_enumerable/huge_product_spec.rb +34 -34
- data/spec/lib/huge_enumerable_spec.rb +641 -641
- metadata +97 -118
@@ -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
|
-
#
|
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.
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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.
|
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,
|
51
|
-
|
52
|
-
super(enumerable, max_array_size, rng)
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def collection_size
|
64
|
-
enum_size
|
65
|
-
end
|
66
|
-
|
67
|
-
|
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
|