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]
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. -
.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 withother
. -
#add(item) ⇒ Vector
(also: #<<, #push)
Return a new
Vector
withitem
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 theVector
, and then returnsself
. -
#delete(obj) ⇒ Vector
Return a new
Vector
with all items which are equal toobj
removed. -
#delete_at(index) ⇒ Vector
Return a new
Vector
with the element atindex
removed. -
#dig(key, *rest) ⇒ Object
Return the value of successively indexing into a nested collection.
-
#drop(n) ⇒ Vector
Drop the first
n
elements and return the rest in a newVector
. -
#drop_while ⇒ Vector, Enumerator
Drop elements up to, but not including, the first element for which the block returns
nil
orfalse
. -
#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 thisVector
contains no items. -
#eql?(other) ⇒ Boolean
Return true if
other
has the same type and contents as thisVector
. -
#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 thisVector
. -
#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 atindex
. -
#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. -
#permutation(n = @size) ⇒ self, Enumerator
Yields all permutations of length
n
of items from theVector
, and then returnsself
. -
#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 theVector
, and then returnsself
. -
#repeated_permutation(n = @size) ⇒ self, Enumerator
When invoked with a block, yields all repeated permutations of length
n
of items from theVector
, and then returnsself
. -
#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 indexcount
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 givenindex
. -
#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 newVector
. -
#take_while ⇒ Vector, Enumerator
Gather elements up to, but not including, the first element for which the block returns
nil
orfalse
, and return them in a newVector
. -
#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
withobject
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 givenindices
, in the order specified byindices
. -
#zip(*others) ⇒ Vector
Combine two vectors by "zipping" them together.
Methods included from Enumerable
#<=>, #==, #compact, #each_index, #grep, #grep_v, #group_by, #inspect, #join, #partition, #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 |
.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 ||= new end |
Instance Method Details
#*(times) ⇒ Vector
Repetition. Return a new Vector
built by concatenating times
copies
of this one together.
778 779 780 781 782 783 |
# File 'lib/immutable/vector.rb', line 778 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
.
631 632 633 634 635 |
# File 'lib/immutable/vector.rb', line 631 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).
1269 1270 1271 1272 1273 1274 1275 |
# File 'lib/immutable/vector.rb', line 1269 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.
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
# File 'lib/immutable/vector.rb', line 1163 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.
1194 1195 1196 |
# File 'lib/immutable/vector.rb', line 1194 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.
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 |
# File 'lib/immutable/vector.rb', line 857 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 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.
504 505 506 |
# File 'lib/immutable/vector.rb', line 504 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
.
400 401 402 403 404 405 406 |
# File 'lib/immutable/vector.rb', line 400 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(&:shift)) end |
#dig(key, *rest) ⇒ Object
Return the value of successively indexing into a nested collection.
If any of the keys is not present, return nil
.
291 292 293 294 295 296 297 298 |
# File 'lib/immutable/vector.rb', line 291 def dig(key, *rest) value = self[key] if rest.empty? || value.nil? value else value.dig(*rest) end end |
#drop(n) ⇒ Vector
Drop the first n
elements and return the rest in a new Vector
.
721 722 723 724 725 726 |
# File 'lib/immutable/vector.rb', line 721 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.
750 751 752 753 |
# File 'lib/immutable/vector.rb', line 750 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.
1331 1332 1333 |
# File 'lib/immutable/vector.rb', line 1331 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.
457 458 459 460 461 |
# File 'lib/immutable/vector.rb', line 457 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
.
1316 1317 1318 1319 1320 |
# File 'lib/immutable/vector.rb', line 1316 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.
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
# File 'lib/immutable/vector.rb', line 822 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
.
531 532 533 534 535 |
# File 'lib/immutable/vector.rb', line 531 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
.
610 611 612 613 614 615 616 617 618 619 620 |
# File 'lib/immutable/vector.rb', line 610 def flatten(level = -1) return self if level == 0 array = 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
.
1324 1325 1326 |
# File 'lib/immutable/vector.rb', line 1324 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.
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/immutable/vector.rb', line 374 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.
516 517 518 519 520 |
# File 'lib/immutable/vector.rb', line 516 def map return enum_for(:map) if not block_given? return self if empty? self.class.new(super) 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.
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 |
# File 'lib/immutable/vector.rb', line 960 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| next 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 perms[0] end self end |
#pop ⇒ Vector
Return a new Vector
with the last element removed. Return self
if
empty.
415 416 417 418 |
# File 'lib/immutable/vector.rb', line 415 def pop return self if @size == 0 replace_suffix(@size-1, []) end |
#product(*vectors) ⇒ Vector #product ⇒ Vector
Cartesian product or multiplication.
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 1090 1091 1092 1093 1094 1095 1096 1097 1098 |
# File 'lib/immutable/vector.rb', line 1057 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? loop do yield build_array[] return self if bump_counters[] end else result = [] loop do 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).
1289 1290 1291 1292 1293 1294 1295 |
# File 'lib/immutable/vector.rb', line 1289 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.
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 |
# File 'lib/immutable/vector.rb', line 910 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.
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 |
# File 'lib/immutable/vector.rb', line 1014 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.
572 573 574 |
# File 'lib/immutable/vector.rb', line 572 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.
474 475 476 477 478 |
# File 'lib/immutable/vector.rb', line 474 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.
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 |
# File 'lib/immutable/vector.rb', line 1242 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.
589 590 591 592 |
# File 'lib/immutable/vector.rb', line 589 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
.
1204 1205 1206 |
# File 'lib/immutable/vector.rb', line 1204 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.
489 490 491 492 |
# File 'lib/immutable/vector.rb', line 489 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
.
440 441 442 |
# File 'lib/immutable/vector.rb', line 440 def shift delete_at(0) end |
#shuffle ⇒ Vector
Return a new Vector
with the same elements as this one, but randomly permuted.
543 544 545 |
# File 'lib/immutable/vector.rb', line 543 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.
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/immutable/vector.rb', line 340 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.
692 693 694 |
# File 'lib/immutable/vector.rb', line 692 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
(#<=>
).
708 709 710 |
# File 'lib/immutable/vector.rb', line 708 def sort_by self.class.new(super) end |
#take(n) ⇒ Vector
Return only the first n
elements in a new Vector
.
736 737 738 739 |
# File 'lib/immutable/vector.rb', line 736 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.
764 765 766 767 |
# File 'lib/immutable/vector.rb', line 764 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.
1301 1302 1303 1304 1305 1306 1307 1308 1309 |
# File 'lib/immutable/vector.rb', line 1301 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.
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
# File 'lib/immutable/vector.rb', line 1117 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) rescue NoMethodError if any? { |x| !x.respond_to?(:size) || !x.respond_to?(:[]) } bad = find { |x| !x.respond_to?(:size) || !x.respond_to?(:[]) } raise TypeError, "'#{bad.inspect}' must respond to #size and #[] to be transposed" else raise end 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.
555 556 557 558 559 560 561 562 563 564 |
# File 'lib/immutable/vector.rb', line 555 def uniq(&block) array = to_a 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 end |
#unshift(object) ⇒ Vector
Return a new Vector
with object
inserted before the first element,
moving the other elements upwards.
429 430 431 |
# File 'lib/immutable/vector.rb', line 429 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.
1218 1219 1220 |
# File 'lib/immutable/vector.rb', line 1218 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.
663 664 665 666 667 668 669 |
# File 'lib/immutable/vector.rb', line 663 def zip(*others) if block_given? super else self.class.new(super) end end |