Class: Immutable::Vector
- Inherits:
-
Object
- Object
- Immutable::Vector
- Includes:
- Enumerable
- Defined in:
- lib/immutable/vector.rb
Overview
A ‘Vector` is an ordered, integer-indexed collection of objects. Like Ruby’s ‘Array`, `Vector` indexing starts at zero and negative indexes count back from the end.
‘Vector` has a similar interface to `Array`. The main difference is methods that would destructively update an `Array` (such as #insert or #delete_at) instead return new `Vectors` and leave the existing one unchanged.
### Creating New Vectors
Immutable::Vector.new([:first, :second, :third])
Immutable::Vector[1, 2, 3, 4, 5]
### Retrieving Items from Vectors
vector = Immutable::Vector[1, 2, 3, 4, 5]
vector[0] # => 1
vector[-1] # => 5
vector[0,3] # => Immutable::Vector[1, 2, 3]
vector[1..-1] # => Immutable::Vector[2, 3, 4, 5]
vector.first # => 1
vector.last # => 5
### Creating Modified Vectors
vector.add(6) # => Immutable::Vector[1, 2, 3, 4, 5, 6]
vector.insert(1, :a, :b) # => Immutable::Vector[1, :a, :b, 2, 3, 4, 5]
vector.delete_at(2) # => Immutable::Vector[1, 2, 4, 5]
vector + [6, 7] # => Immutable::Vector[1, 2, 3, 4, 5, 6, 7]
Constant Summary collapse
- BLOCK_SIZE =
32- INDEX_MASK =
BLOCK_SIZE - 1
- BITS_PER_LEVEL =
5
Instance Attribute Summary collapse
-
#size ⇒ Integer
(also: #length)
readonly
Return the number of items in this ‘Vector`.
Class Method Summary collapse
-
.[](*items) ⇒ Vector
Create a new ‘Vector` populated with the given items.
-
.alloc(root, size, levels) ⇒ Vector
“Raw” allocation of a new ‘Vector`.
-
.empty ⇒ Vector
Return an empty ‘Vector`.
Instance Method Summary collapse
-
#*(times) ⇒ Vector
Repetition.
-
#+(other) ⇒ Vector
(also: #concat)
Return a new ‘Vector` built by concatenating this one with `other`.
-
#add(item) ⇒ Vector
(also: #<<, #push)
Return a new ‘Vector` with `item` added after the last occupied position.
-
#assoc(obj) ⇒ Object
Assumes all elements are nested, indexable collections, and searches through them, comparing ‘obj` with the first element of each nested collection.
-
#bsearch {|element| ... } ⇒ Object
Finds a value from this ‘Vector` which meets the condition defined by the provided block, using a binary search.
-
#clear ⇒ Vector
Return an empty ‘Vector` instance, of the same class as this one.
-
#combination(n) ⇒ self, Enumerator
When invoked with a block, yields all combinations of length ‘n` of items from the `Vector`, and then returns `self`.
-
#delete(obj) ⇒ Vector
Return a new ‘Vector` with all items which are equal to `obj` removed.
-
#delete_at(index) ⇒ Vector
Return a new ‘Vector` with the element at `index` removed.
-
#drop(n) ⇒ Vector
Drop the first ‘n` elements and return the rest in a new `Vector`.
-
#drop_while ⇒ Vector, Enumerator
Drop elements up to, but not including, the first element for which the block returns ‘nil` or `false`.
-
#dup ⇒ Vector
(also: #clone)
Return ‘self`.
-
#each(&block) ⇒ self, Enumerator
Call the given block once for each item in the vector, passing each item from first to last successively to the block.
-
#empty? ⇒ Boolean
Return ‘true` if this `Vector` contains no items.
-
#eql?(other) ⇒ Boolean
Return true if ‘other` has the same type and contents as this `Vector`.
-
#fetch(index, default = (missing_default = true)) ⇒ Object
Retrieve the value at ‘index` with optional default.
-
#fill(object, index = 0, length = nil) ⇒ Vector
Replace a range of indexes with the given object.
-
#first ⇒ Object
Return the first item in the ‘Vector`.
-
#flat_map ⇒ Vector
Return a new ‘Vector` with the concatenated results of running the block once for every element in this `Vector`.
-
#flatten(level = -1)) ⇒ Vector
Return a new ‘Vector` with all nested vectors and arrays recursively “flattened out”.
-
#get(index) ⇒ Object
(also: #at)
Retrieve the item at ‘index`.
-
#hash ⇒ Integer
See ‘Object#hash`.
-
#initialize(items = [].freeze) ⇒ Vector
constructor
A new instance of Vector.
-
#insert(index, *items) ⇒ Vector
Return a new ‘Vector` with the given values inserted before the element at `index`.
-
#last ⇒ Object
Return the last item in the ‘Vector`.
-
#map ⇒ Vector, Enumerator
(also: #collect)
Invoke the given block once for each item in the vector, and return a new ‘Vector` containing the values returned by the block.
- #marshal_dump ⇒ ::Array
- #marshal_load(array) ⇒ Object
-
#permutation(n = @size) ⇒ self, Enumerator
Yields all permutations of length ‘n` of items from the `Vector`, and then returns `self`.
-
#pop ⇒ Vector
Return a new ‘Vector` with the last element removed.
-
#product(*vectors) ⇒ Vector
Cartesian product or multiplication.
-
#rassoc(obj) ⇒ Object
Assumes all elements are nested, indexable collections, and searches through them, comparing ‘obj` with the second element of each nested collection.
-
#repeated_combination(n) ⇒ self, Enumerator
When invoked with a block, yields all repeated combinations of length ‘n` of items from the `Vector`, and then returns `self`.
-
#repeated_permutation(n = @size) ⇒ self, Enumerator
When invoked with a block, yields all repeated permutations of length ‘n` of items from the `Vector`, and then returns `self`.
-
#reverse ⇒ Vector
Return a new ‘Vector` with the same elements as this one, but in reverse order.
-
#reverse_each(&block) ⇒ self
Call the given block once for each item in the vector, from last to first.
-
#rindex(obj = (missing_arg = true)) ⇒ Integer
Find the index of an element, starting from the end of the vector.
-
#rotate(count = 1) ⇒ Vector
Return a new ‘Vector` with the same elements, but rotated so that the one at index `count` is the first element of the new vector.
-
#sample ⇒ Object
Return a randomly chosen item from this ‘Vector`.
-
#select {|element| ... } ⇒ Vector
(also: #find_all, #keep_if)
Return a new ‘Vector` containing all elements for which the given block returns true.
-
#set(index, item = yield(get(index))) ⇒ Vector
Return a new ‘Vector` with a new value at the given `index`.
-
#shift ⇒ Vector
Return a new ‘Vector` with the first element removed.
-
#shuffle ⇒ Vector
Return a new ‘Vector` with the same elements as this one, but randomly permuted.
-
#slice(arg, length = (missing_length = true)) ⇒ Object
(also: #[])
Return specific objects from the ‘Vector`.
-
#sort ⇒ Vector
Return a new ‘Vector` with the same items, but sorted.
-
#sort_by {|element| ... } ⇒ Vector
Return a new ‘Vector` with the same items, but sorted.
-
#take(n) ⇒ Vector
Return only the first ‘n` elements in a new `Vector`.
-
#take_while ⇒ Vector, Enumerator
Gather elements up to, but not including, the first element for which the block returns ‘nil` or `false`, and return them in a new `Vector`.
-
#to_a ⇒ Array
(also: #to_ary)
Return an ‘Array` with the same elements, in the same order.
-
#transpose ⇒ Vector
Assume all elements are vectors or arrays and transpose the rows and columns.
-
#uniq(&block) ⇒ Vector
Return a new ‘Vector` with no duplicate elements, as determined by `#hash` and `#eql?`.
-
#unshift(object) ⇒ Vector
Return a new ‘Vector` with `object` inserted before the first element, moving the other elements upwards.
-
#update_in(*key_path) {|value| ... } ⇒ Vector
Return a new ‘Vector` with a deeply nested value modified to the result of the given code block.
-
#values_at(*indices) ⇒ Vector
Return a new ‘Vector` with only the elements at the given `indices`, in the order specified by `indices`.
-
#zip(*others) ⇒ Vector
Combine two vectors by “zipping” them together.
Methods included from Enumerable
#<=>, #==, #compact, #each_index, #grep, #group_by, #inspect, #join, #partition, #pretty_print, #reject, #sum, #to_set
Methods included from Enumerable
Constructor Details
#initialize(items = [].freeze) ⇒ Vector
Returns a new instance of Vector.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/immutable/vector.rb', line 82 def initialize(items=[].freeze) items = items.to_a if items.size <= 32 items = items.dup.freeze if !items.frozen? @root, @size, @levels = items, items.size, 0 else root, size, levels = items, items.size, 0 while root.size > 32 root = root.each_slice(32).to_a levels += 1 end @root, @size, @levels = root.freeze, size, levels end freeze end |
Instance Attribute Details
#size ⇒ Integer (readonly) Also known as: length
Return the number of items in this ‘Vector`
50 51 52 |
# File 'lib/immutable/vector.rb', line 50 def size @size end |
Class Method Details
.[](*items) ⇒ Vector
Create a new ‘Vector` populated with the given items.
56 57 58 |
# File 'lib/immutable/vector.rb', line 56 def [](*items) new(items.freeze) end |
.alloc(root, size, levels) ⇒ Vector
“Raw” allocation of a new ‘Vector`. Used internally to create a new instance quickly after building a modified trie.
73 74 75 76 77 78 79 |
# File 'lib/immutable/vector.rb', line 73 def alloc(root, size, levels) obj = allocate obj.instance_variable_set(:@root, root) obj.instance_variable_set(:@size, size) obj.instance_variable_set(:@levels, levels) obj.freeze end |
.empty ⇒ Vector
Return an empty ‘Vector`. If used on a subclass, returns an empty instance of that class.
64 65 66 |
# File 'lib/immutable/vector.rb', line 64 def empty @empty ||= self.new end |
Instance Method Details
#*(times) ⇒ Vector
Repetition. Return a new ‘Vector` built by concatenating `times` copies of this one together.
768 769 770 771 772 773 |
# File 'lib/immutable/vector.rb', line 768 def *(times) return self.class.empty if times == 0 return self if times == 1 result = (to_a * times) result.is_a?(Array) ? self.class.new(result) : result end |
#+(other) ⇒ Vector Also known as: concat
Return a new ‘Vector` built by concatenating this one with `other`. `other` can be any object which is convertible to an `Array` using `#to_a`.
621 622 623 624 625 |
# File 'lib/immutable/vector.rb', line 621 def +(other) other = other.to_a other = other.dup if other.frozen? replace_suffix(@size, other) end |
#add(item) ⇒ Vector Also known as: <<, push
Return a new ‘Vector` with `item` added after the last occupied position.
132 133 134 |
# File 'lib/immutable/vector.rb', line 132 def add(item) update_root(@size, item) end |
#assoc(obj) ⇒ Object
Assumes all elements are nested, indexable collections, and searches through them, comparing ‘obj` with the first element of each nested collection. Return the first nested collection which matches, or `nil` if none is found. Behaviour is undefined when elements do not meet assumptions (i.e. are not indexable collections).
1253 1254 1255 1256 1257 1258 1259 |
# File 'lib/immutable/vector.rb', line 1253 def assoc(obj) each do |array| next if !array.respond_to?(:[]) return array if obj == array[0] end nil end |
#bsearch {|element| ... } ⇒ Object
Finds a value from this ‘Vector` which meets the condition defined by the provided block, using a binary search. The vector must already be sorted with respect to the block. See Ruby’s ‘Array#bsearch` for details, behaviour is equivalent.
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 |
# File 'lib/immutable/vector.rb', line 1147 def bsearch return enum_for(:bsearch) if not block_given? low, high, result = 0, @size, nil while low < high mid = (low + ((high - low) >> 1)) val = get(mid) v = yield val if v.is_a? Numeric if v == 0 return val elsif v > 0 high = mid else low = mid + 1 end elsif v == true result = val high = mid elsif !v low = mid + 1 else raise TypeError, "wrong argument type #{v.class} (must be numeric, true, false, or nil)" end end result end |
#clear ⇒ Vector
Return an empty ‘Vector` instance, of the same class as this one. Useful if you have multiple subclasses of `Vector` and want to treat them polymorphically.
1178 1179 1180 |
# File 'lib/immutable/vector.rb', line 1178 def clear self.class.empty end |
#combination(n) ⇒ self, Enumerator
When invoked with a block, yields all combinations of length ‘n` of items from the `Vector`, and then returns `self`. There is no guarantee about which order the combinations will be yielded.
If no block is given, an ‘Enumerator` is returned instead.
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 |
# File 'lib/immutable/vector.rb', line 847 def combination(n) return enum_for(:combination, n) if not block_given? return self if n < 0 || @size < n if n == 0 yield [] elsif n == 1 each { |item| yield [item] } elsif n == @size yield self.to_a else combos = lambda do |result,index,remaining| while @size - index > remaining if remaining == 1 yield result.dup << get(index) else combos[result.dup << get(index), index+1, remaining-1] end index += 1 end index.upto(@size-1) { |i| result << get(i) } yield result end combos[[], 0, n] end self end |
#delete(obj) ⇒ Vector
Return a new ‘Vector` with all items which are equal to `obj` removed. `#==` is used for checking equality.
486 487 488 |
# File 'lib/immutable/vector.rb', line 486 def delete(obj) select { |item| item != obj } end |
#delete_at(index) ⇒ Vector
Return a new ‘Vector` with the element at `index` removed. If the given `index` does not exist, return `self`.
382 383 384 385 386 387 388 |
# File 'lib/immutable/vector.rb', line 382 def delete_at(index) return self if index >= @size || index < -@size index += @size if index < 0 suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, []) replace_suffix(index, suffix.tap { |a| a.shift }) end |
#drop(n) ⇒ Vector
Drop the first ‘n` elements and return the rest in a new `Vector`.
711 712 713 714 715 716 |
# File 'lib/immutable/vector.rb', line 711 def drop(n) return self if n == 0 return self.class.empty if n >= @size raise ArgumentError, "attempt to drop negative size" if n < 0 self.class.new(flatten_suffix(@root, @levels * BITS_PER_LEVEL, n, [])) end |
#drop_while ⇒ Vector, Enumerator
Drop elements up to, but not including, the first element for which the block returns ‘nil` or `false`. Gather the remaining elements into a new `Vector`. If no block is given, an `Enumerator` is returned instead.
740 741 742 743 |
# File 'lib/immutable/vector.rb', line 740 def drop_while return enum_for(:drop_while) if not block_given? self.class.new(super) end |
#dup ⇒ Vector Also known as: clone
Return ‘self`. Since this is an immutable object duplicates are equivalent.
1315 1316 1317 |
# File 'lib/immutable/vector.rb', line 1315 def dup self end |
#each(&block) ⇒ self, Enumerator
Call the given block once for each item in the vector, passing each item from first to last successively to the block. If no block is given, an ‘Enumerator` is returned instead.
439 440 441 442 443 |
# File 'lib/immutable/vector.rb', line 439 def each(&block) return to_enum unless block_given? traverse_depth_first(@root, @levels, &block) self end |
#empty? ⇒ Boolean
Return ‘true` if this `Vector` contains no items.
101 102 103 |
# File 'lib/immutable/vector.rb', line 101 def empty? @size == 0 end |
#eql?(other) ⇒ Boolean
Return true if ‘other` has the same type and contents as this `Vector`.
1300 1301 1302 1303 1304 |
# File 'lib/immutable/vector.rb', line 1300 def eql?(other) return true if other.equal?(self) return false unless instance_of?(other.class) && @size == other.size @root.eql?(other.instance_variable_get(:@root)) end |
#fetch(index) ⇒ Object #fetch(index) {|index| ... } ⇒ Object #fetch(index, default) ⇒ Object
Retrieve the value at ‘index` with optional default.
270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/immutable/vector.rb', line 270 def fetch(index, default = (missing_default = true)) if index >= -@size && index < @size get(index) elsif block_given? yield(index) elsif !missing_default default else raise IndexError, "index #{index} outside of vector bounds" end end |
#fill(object) ⇒ Vector #fill(object, index) ⇒ Vector #fill(object, index, length) ⇒ Vector
Replace a range of indexes with the given object.
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
# File 'lib/immutable/vector.rb', line 812 def fill(object, index = 0, length = nil) raise IndexError if index < -@size index += @size if index < 0 length ||= @size - index # to the end of the array, if no length given if index < @size suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, []) suffix.fill(object, 0, length) elsif index == @size suffix = Array.new(length, object) else suffix = Array.new(index - @size, nil).concat(Array.new(length, object)) index = @size end replace_suffix(index, suffix) end |
#first ⇒ Object
Return the first item in the ‘Vector`. If the vector is empty, return `nil`.
111 112 113 |
# File 'lib/immutable/vector.rb', line 111 def first get(0) end |
#flat_map ⇒ Vector
Return a new ‘Vector` with the concatenated results of running the block once for every element in this `Vector`.
513 514 515 516 517 |
# File 'lib/immutable/vector.rb', line 513 def flat_map return enum_for(:flat_map) if not block_given? return self if empty? self.class.new(super) end |
#flatten(level = -1)) ⇒ Vector
Return a new ‘Vector` with all nested vectors and arrays recursively “flattened out”. That is, their elements inserted into the new `Vector` in the place where the nested array/vector originally was. If an optional `level` argument is provided, the flattening will only be done recursively that number of times. A `level` of 0 means not to flatten at all, 1 means to only flatten nested arrays/vectors which are directly contained within this `Vector`.
600 601 602 603 604 605 606 607 608 609 610 |
# File 'lib/immutable/vector.rb', line 600 def flatten(level = -1) return self if level == 0 array = self.to_a if array.frozen? self.class.new(array.flatten(level).freeze) elsif array.flatten!(level) # returns nil if no changes were made self.class.new(array.freeze) else self end end |
#get(index) ⇒ Object Also known as: at
Retrieve the item at ‘index`. If there is none (either the provided index is too high or too low), return `nil`.
223 224 225 226 227 228 |
# File 'lib/immutable/vector.rb', line 223 def get(index) return nil if @size == 0 index += @size if index < 0 return nil if index >= @size || index < 0 leaf_node_for(@root, @levels * BITS_PER_LEVEL, index)[index & INDEX_MASK] end |
#hash ⇒ Integer
See ‘Object#hash`.
1308 1309 1310 |
# File 'lib/immutable/vector.rb', line 1308 def hash reduce(0) { |hash, item| (hash << 5) - hash + item.hash } end |
#insert(index, *items) ⇒ Vector
Return a new ‘Vector` with the given values inserted before the element at `index`. If `index` is greater than the current length, `nil` values are added to pad the `Vector` to the required size.
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/immutable/vector.rb', line 356 def insert(index, *items) raise IndexError if index < -@size index += @size if index < 0 if index < @size suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, []) suffix.unshift(*items) elsif index == @size suffix = items else suffix = Array.new(index - @size, nil).concat(items) index = @size end replace_suffix(index, suffix) end |
#last ⇒ Object
Return the last item in the ‘Vector`. If the vector is empty, return `nil`.
121 122 123 |
# File 'lib/immutable/vector.rb', line 121 def last get(-1) end |
#map ⇒ Vector, Enumerator Also known as: collect
Invoke the given block once for each item in the vector, and return a new ‘Vector` containing the values returned by the block. If no block is provided, return an enumerator.
498 499 500 501 502 |
# File 'lib/immutable/vector.rb', line 498 def map return enum_for(:map) if not block_given? return self if empty? self.class.new(super) end |
#marshal_dump ⇒ ::Array
1322 1323 1324 |
# File 'lib/immutable/vector.rb', line 1322 def marshal_dump to_a end |
#marshal_load(array) ⇒ Object
1327 1328 1329 |
# File 'lib/immutable/vector.rb', line 1327 def marshal_load(array) initialize(array.freeze) end |
#permutation(n = @size) ⇒ self, Enumerator
Yields all permutations of length ‘n` of items from the `Vector`, and then returns `self`. If no length `n` is specified, permutations of all elements will be yielded.
There is no guarantee about which order the permutations will be yielded in.
If no block is given, an ‘Enumerator` is returned instead.
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 |
# File 'lib/immutable/vector.rb', line 950 def permutation(n = @size) return enum_for(:permutation, n) if not block_given? if n < 0 || @size < n # yield nothing elsif n == 0 yield [] elsif n == 1 each { |item| yield [item] } else used, result = [], [] perms = lambda do |index| 0.upto(@size-1) do |i| if !used[i] result[index] = get(i) if index < n-1 used[i] = true perms[index+1] used[i] = false else yield result.dup end end end end perms[0] end self end |
#pop ⇒ Vector
Return a new ‘Vector` with the last element removed. Return `self` if empty.
397 398 399 400 |
# File 'lib/immutable/vector.rb', line 397 def pop return self if @size == 0 replace_suffix(@size-1, []) end |
#product(*vectors) ⇒ Vector #product ⇒ Vector
Cartesian product or multiplication.
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
# File 'lib/immutable/vector.rb', line 1048 def product(*vectors) # if no vectors passed, return "product" as in result of multiplying all items return super if vectors.empty? vectors.unshift(self) if vectors.any?(&:empty?) return block_given? ? self : [] end counters = Array.new(vectors.size, 0) bump_counters = lambda do i = vectors.size-1 counters[i] += 1 while counters[i] == vectors[i].size counters[i] = 0 i -= 1 return true if i == -1 # we are done counters[i] += 1 end false # not done yet end build_array = lambda do array = [] counters.each_with_index { |index,i| array << vectors[i][index] } array end if block_given? while true yield build_array[] return self if bump_counters[] end else result = [] while true result << build_array[] return result if bump_counters[] end end end |
#rassoc(obj) ⇒ Object
Assumes all elements are nested, indexable collections, and searches through them, comparing ‘obj` with the second element of each nested collection. Return the first nested collection which matches, or `nil` if none is found. Behaviour is undefined when elements do not meet assumptions (i.e. are not indexable collections).
1273 1274 1275 1276 1277 1278 1279 |
# File 'lib/immutable/vector.rb', line 1273 def rassoc(obj) each do |array| next if !array.respond_to?(:[]) return array if obj == array[1] end nil end |
#repeated_combination(n) ⇒ self, Enumerator
When invoked with a block, yields all repeated combinations of length ‘n` of items from the `Vector`, and then returns `self`. A “repeated combination” is one in which any item from the `Vector` can appear consecutively any number of times.
There is no guarantee about which order the combinations will be yielded in.
If no block is given, an ‘Enumerator` is returned instead.
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
# File 'lib/immutable/vector.rb', line 900 def repeated_combination(n) return enum_for(:repeated_combination, n) if not block_given? if n < 0 # yield nothing elsif n == 0 yield [] elsif n == 1 each { |item| yield [item] } elsif @size == 0 # yield nothing else combos = lambda do |result,index,remaining| while index < @size-1 if remaining == 1 yield result.dup << get(index) else combos[result.dup << get(index), index, remaining-1] end index += 1 end item = get(index) remaining.times { result << item } yield result end combos[[], 0, n] end self end |
#repeated_permutation(n = @size) ⇒ self, Enumerator
When invoked with a block, yields all repeated permutations of length ‘n` of items from the `Vector`, and then returns `self`. A “repeated permutation” is one where any item from the `Vector` can appear any number of times, and in any position (not just consecutively)
If no length ‘n` is specified, permutations of all elements will be yielded. There is no guarantee about which order the permutations will be yielded in.
If no block is given, an ‘Enumerator` is returned instead.
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
# File 'lib/immutable/vector.rb', line 1005 def repeated_permutation(n = @size) return enum_for(:repeated_permutation, n) if not block_given? if n < 0 # yield nothing elsif n == 0 yield [] elsif n == 1 each { |item| yield [item] } else result = [] perms = lambda do |index| 0.upto(@size-1) do |i| result[index] = get(i) if index < n-1 perms[index+1] else yield result.dup end end end perms[0] end self end |
#reverse ⇒ Vector
Return a new ‘Vector` with the same elements as this one, but in reverse order.
562 563 564 |
# File 'lib/immutable/vector.rb', line 562 def reverse self.class.new(((array = to_a).frozen? ? array.reverse : array.reverse!).freeze) end |
#reverse_each(&block) ⇒ self
Call the given block once for each item in the vector, from last to first.
456 457 458 459 460 |
# File 'lib/immutable/vector.rb', line 456 def reverse_each(&block) return enum_for(:reverse_each) unless block_given? reverse_traverse_depth_first(@root, @levels, &block) self end |
#rindex(obj) ⇒ Integer #rindex {|element| ... } ⇒ Integer
Find the index of an element, starting from the end of the vector. Returns ‘nil` if no element is found.
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
# File 'lib/immutable/vector.rb', line 1226 def rindex(obj = (missing_arg = true)) i = @size - 1 if missing_arg if block_given? reverse_each { |item| return i if yield item; i -= 1 } nil else enum_for(:rindex) end else reverse_each { |item| return i if item == obj; i -= 1 } nil end end |
#rotate(count = 1) ⇒ Vector
Return a new ‘Vector` with the same elements, but rotated so that the one at index `count` is the first element of the new vector. If `count` is positive, the elements will be shifted left, and those shifted past the lowest position will be moved to the end. If `count` is negative, the elements will be shifted right, and those shifted past the last position will be moved to the beginning.
579 580 581 582 |
# File 'lib/immutable/vector.rb', line 579 def rotate(count = 1) return self if (count % @size) == 0 self.class.new(((array = to_a).frozen? ? array.rotate(count) : array.rotate!(count)).freeze) end |
#sample ⇒ Object
Return a randomly chosen item from this ‘Vector`. If the vector is empty, return `nil`.
1188 1189 1190 |
# File 'lib/immutable/vector.rb', line 1188 def sample get(rand(@size)) end |
#select {|element| ... } ⇒ Vector Also known as: find_all, keep_if
Return a new ‘Vector` containing all elements for which the given block returns true.
471 472 473 474 |
# File 'lib/immutable/vector.rb', line 471 def select return enum_for(:select) unless block_given? reduce(self.class.empty) { |vector, item| yield(item) ? vector.add(item) : vector } end |
#set(index, item) ⇒ Vector #set(index) {|existing| ... } ⇒ Vector
Return a new ‘Vector` with a new value at the given `index`. If `index` is greater than the length of the vector, the returned vector will be padded with `nil`s to the correct size.
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/immutable/vector.rb', line 165 def set(index, item = yield(get(index))) raise IndexError, "index #{index} outside of vector bounds" if index < -@size index += @size if index < 0 if index > @size suffix = Array.new(index - @size, nil) suffix << item replace_suffix(@size, suffix) else update_root(index, item) end end |
#shift ⇒ Vector
Return a new ‘Vector` with the first element removed. If empty, return `self`.
422 423 424 |
# File 'lib/immutable/vector.rb', line 422 def shift delete_at(0) end |
#shuffle ⇒ Vector
Return a new ‘Vector` with the same elements as this one, but randomly permuted.
525 526 527 |
# File 'lib/immutable/vector.rb', line 525 def shuffle self.class.new(((array = to_a).frozen? ? array.shuffle : array.shuffle!).freeze) end |
#vector.slice(index) ⇒ Object #vector.slice(index, length) ⇒ Vector #vector.slice(index..end) ⇒ Vector Also known as: []
Return specific objects from the ‘Vector`. All overloads return `nil` if the starting index is out of range.
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/immutable/vector.rb', line 322 def slice(arg, length = (missing_length = true)) if missing_length if arg.is_a?(Range) from, to = arg.begin, arg.end from += @size if from < 0 to += @size if to < 0 to += 1 if !arg.exclude_end? length = to - from length = 0 if length < 0 subsequence(from, length) else get(arg) end else arg += @size if arg < 0 subsequence(arg, length) end end |
#sort ⇒ Vector #sort {|a, b| ... } ⇒ Vector
Return a new ‘Vector` with the same items, but sorted.
682 683 684 |
# File 'lib/immutable/vector.rb', line 682 def sort self.class.new(super) end |
#sort_by {|element| ... } ⇒ Vector
Return a new ‘Vector` with the same items, but sorted. The sort order is determined by mapping the items through the given block to obtain sort keys, and then sorting the keys according to their natural sort order (`#<=>`).
698 699 700 |
# File 'lib/immutable/vector.rb', line 698 def sort_by self.class.new(super) end |
#take(n) ⇒ Vector
Return only the first ‘n` elements in a new `Vector`.
726 727 728 729 |
# File 'lib/immutable/vector.rb', line 726 def take(n) return self if n >= @size self.class.new(super) end |
#take_while ⇒ Vector, Enumerator
Gather elements up to, but not including, the first element for which the block returns ‘nil` or `false`, and return them in a new `Vector`. If no block is given, an `Enumerator` is returned instead.
754 755 756 757 |
# File 'lib/immutable/vector.rb', line 754 def take_while return enum_for(:take_while) if not block_given? self.class.new(super) end |
#to_a ⇒ Array Also known as: to_ary
Return an ‘Array` with the same elements, in the same order. The returned `Array` may or may not be frozen.
1285 1286 1287 1288 1289 1290 1291 1292 1293 |
# File 'lib/immutable/vector.rb', line 1285 def to_a if @levels == 0 # When initializing a Vector with 32 or less items, we always make # sure @root is frozen, so we can return it directly here @root else flatten_node(@root, @levels * BITS_PER_LEVEL, []) end end |
#transpose ⇒ Vector
Assume all elements are vectors or arrays and transpose the rows and columns. In other words, take the first element of each nested vector/array and gather them together into a new ‘Vector`. Do likewise for the second, third, and so on down to the end of each nested vector/array. Gather all the resulting `Vectors` into a new `Vector` and return it.
This operation is closely related to #zip. The result is almost the same as calling #zip on the first nested vector/array with the others supplied as arguments.
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 |
# File 'lib/immutable/vector.rb', line 1108 def transpose return self.class.empty if empty? result = Array.new(first.size) { [] } 0.upto(@size-1) do |i| source = get(i) if source.size != result.size raise IndexError, "element size differs (#{source.size} should be #{result.size})" end 0.upto(result.size-1) do |j| result[j].push(source[j]) end end result.map! { |a| self.class.new(a) } self.class.new(result) end |
#uniq(&block) ⇒ Vector
Return a new ‘Vector` with no duplicate elements, as determined by `#hash` and `#eql?`. For each group of equivalent elements, only the first will be retained.
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
# File 'lib/immutable/vector.rb', line 537 def uniq(&block) array = self.to_a if block_given? if array.frozen? self.class.new(array.uniq(&block).freeze) elsif array.uniq!(&block) # returns nil if no changes were made self.class.new(array.freeze) else self end elsif array.frozen? self.class.new(array.uniq.freeze) elsif array.uniq! # returns nil if no changes were made self.class.new(array.freeze) else self end end |
#unshift(object) ⇒ Vector
Return a new ‘Vector` with `object` inserted before the first element, moving the other elements upwards.
411 412 413 |
# File 'lib/immutable/vector.rb', line 411 def unshift(object) insert(0, object) end |
#update_in(*key_path) {|value| ... } ⇒ Vector
Return a new ‘Vector` with a deeply nested value modified to the result of the given code block. When traversing the nested `Vector`s and `Hash`es, non-existing keys are created with empty `Hash` values.
The code block receives the existing value of the deeply nested key (or ‘nil` if it doesn’t exist). This is useful for “transforming” the value associated with a certain key.
Note that the original ‘Vector` and sub-`Vector`s and sub-`Hash`es are left unmodified; new data structure copies are created along the path wherever needed.
198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/immutable/vector.rb', line 198 def update_in(*key_path, &block) if key_path.empty? raise ArgumentError, "must have at least one key in path" end key = key_path[0] if key_path.size == 1 new_value = block.call(get(key)) else value = fetch(key, Immutable::EmptyHash) new_value = value.update_in(*key_path[1..-1], &block) end set(key, new_value) end |
#values_at(*indices) ⇒ Vector
Return a new ‘Vector` with only the elements at the given `indices`, in the order specified by `indices`. If any of the `indices` do not exist, `nil`s will appear in their places.
1202 1203 1204 |
# File 'lib/immutable/vector.rb', line 1202 def values_at(*indices) self.class.new(indices.map { |i| get(i) }.freeze) end |
#zip(*others) ⇒ Vector #zip(*others) {|pair| ... } ⇒ nil
Combine two vectors by “zipping” them together. ‘others` should be arrays and/or vectors. The corresponding elements from this `Vector` and each of `others` (that is, the elements with the same indices) will be gathered into arrays.
If ‘others` contains fewer elements than this vector, `nil` will be used for padding.
653 654 655 656 657 658 659 |
# File 'lib/immutable/vector.rb', line 653 def zip(*others) if block_given? super else self.class.new(super) end end |