Class: Immutable::Vector
- Inherits:
-
Object
- Object
- Immutable::Vector
- Includes:
- Enumerable
- Defined in:
- lib/immutable/_core.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
Vectorpopulated 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
Vectorbuilt by concatenating this one withother. -
#add(item) ⇒ Vector
(also: #<<, #push)
Return a new
Vectorwithitemadded after the last occupied position. -
#assoc(obj) ⇒ Object
Assumes all elements are nested, indexable collections, and searches through them, comparing
objwith the first element of each nested collection. -
#bsearch {|element| ... } ⇒ Object
Finds a value from this
Vectorwhich meets the condition defined by the provided block, using a binary search. -
#clear ⇒ Vector
Return an empty
Vectorinstance, of the same class as this one. -
#combination(n) ⇒ self, Enumerator
When invoked with a block, yields all combinations of length
nof items from theVector, and then returnsself. -
#delete(obj) ⇒ Vector
Return a new
Vectorwith all items which are equal toobjremoved. -
#delete_at(index) ⇒ Vector
Return a new
Vectorwith the element atindexremoved. -
#dig(key, *rest) ⇒ Object
Return the value of successively indexing into a nested collection.
-
#drop(n) ⇒ Vector
Drop the first
nelements 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
nilorfalse. -
#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
trueif thisVectorcontains no items. -
#eql?(other) ⇒ Boolean
Return true if
otherhas the same type and contents as thisVector. -
#fetch(index, default = (missing_default = true)) ⇒ Object
Retrieve the value at
indexwith 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
Vectorwith the concatenated results of running the block once for every element in thisVector. -
#flatten(level = -1)) ⇒ Vector
Return a new
Vectorwith 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
Vectorwith 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
Vectorcontaining the values returned by the block. - #marshal_dump ⇒ ::Array
- #marshal_load(array) ⇒ Object
-
#permutation(n = @size) ⇒ self, Enumerator
Yields all permutations of length
nof items from theVector, and then returnsself. -
#pop ⇒ Vector
Return a new
Vectorwith 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
objwith the second element of each nested collection. -
#repeated_combination(n) ⇒ self, Enumerator
When invoked with a block, yields all repeated combinations of length
nof items from theVector, and then returnsself. -
#repeated_permutation(n = @size) ⇒ self, Enumerator
When invoked with a block, yields all repeated permutations of length
nof items from theVector, and then returnsself. -
#reverse ⇒ Vector
Return a new
Vectorwith 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
Vectorwith the same elements, but rotated so that the one at indexcountis 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
Vectorcontaining all elements for which the given block returns true. -
#set(index, item = yield(get(index))) ⇒ Vector
Return a new
Vectorwith a new value at the givenindex. -
#shift ⇒ Vector
Return a new
Vectorwith the first element removed. -
#shuffle ⇒ Vector
Return a new
Vectorwith 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
Vectorwith the same items, but sorted. -
#sort_by {|element| ... } ⇒ Vector
Return a new
Vectorwith the same items, but sorted. -
#take(n) ⇒ Vector
Return only the first
nelements in a newVector. -
#take_while ⇒ Vector, Enumerator
Gather elements up to, but not including, the first element for which the block returns
nilorfalse, and return them in a newVector. -
#to_a ⇒ Array
(also: #to_ary)
Return an
Arraywith 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
Vectorwith no duplicate elements, as determined by#hashand#eql?. -
#unshift(object) ⇒ Vector
Return a new
Vectorwithobjectinserted before the first element, moving the other elements upwards. -
#update_in(*key_path) {|value| ... } ⇒ Vector
Return a new
Vectorwith a deeply nested value modified to the result of the given code block. -
#values_at(*indices) ⇒ Vector
Return a new
Vectorwith 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, #pretty_print, #reject, #sum, #to_set
Methods included from Enumerable
Constructor Details
#initialize(items = [].freeze) ⇒ Vector
Returns a new instance of Vector.
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 |
# File 'lib/immutable/_core.rb', line 1019 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
987 988 989 |
# File 'lib/immutable/_core.rb', line 987 def size @size end |
Class Method Details
.[](*items) ⇒ Vector
Create a new Vector populated with the given items.
993 994 995 |
# File 'lib/immutable/_core.rb', line 993 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.
1010 1011 1012 1013 1014 1015 1016 |
# File 'lib/immutable/_core.rb', line 1010 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.
1001 1002 1003 |
# File 'lib/immutable/_core.rb', line 1001 def empty @empty ||= new end |
Instance Method Details
#*(times) ⇒ Vector
Repetition. Return a new Vector built by concatenating times copies of this one together.
1715 1716 1717 1718 1719 1720 |
# File 'lib/immutable/_core.rb', line 1715 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.
1568 1569 1570 1571 1572 |
# File 'lib/immutable/_core.rb', line 1568 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.
1069 1070 1071 |
# File 'lib/immutable/_core.rb', line 1069 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).
2206 2207 2208 2209 2210 2211 2212 |
# File 'lib/immutable/_core.rb', line 2206 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.
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 |
# File 'lib/immutable/_core.rb', line 2100 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.
2131 2132 2133 |
# File 'lib/immutable/_core.rb', line 2131 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.
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 |
# File 'lib/immutable/_core.rb', line 1794 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.
1441 1442 1443 |
# File 'lib/immutable/_core.rb', line 1441 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.
1337 1338 1339 1340 1341 1342 1343 |
# File 'lib/immutable/_core.rb', line 1337 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.
1228 1229 1230 1231 1232 1233 1234 1235 |
# File 'lib/immutable/_core.rb', line 1228 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.
1658 1659 1660 1661 1662 1663 |
# File 'lib/immutable/_core.rb', line 1658 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.
1687 1688 1689 1690 |
# File 'lib/immutable/_core.rb', line 1687 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.
2268 2269 2270 |
# File 'lib/immutable/_core.rb', line 2268 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.
1394 1395 1396 1397 1398 |
# File 'lib/immutable/_core.rb', line 1394 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.
1038 1039 1040 |
# File 'lib/immutable/_core.rb', line 1038 def empty? @size == 0 end |
#eql?(other) ⇒ Boolean
Return true if other has the same type and contents as this Vector.
2253 2254 2255 2256 2257 |
# File 'lib/immutable/_core.rb', line 2253 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.
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 |
# File 'lib/immutable/_core.rb', line 1207 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.
1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 |
# File 'lib/immutable/_core.rb', line 1759 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.
1048 1049 1050 |
# File 'lib/immutable/_core.rb', line 1048 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.
1468 1469 1470 1471 1472 |
# File 'lib/immutable/_core.rb', line 1468 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.
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 |
# File 'lib/immutable/_core.rb', line 1547 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.
1160 1161 1162 1163 1164 1165 |
# File 'lib/immutable/_core.rb', line 1160 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`.
2261 2262 2263 |
# File 'lib/immutable/_core.rb', line 2261 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.
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 |
# File 'lib/immutable/_core.rb', line 1311 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.
1058 1059 1060 |
# File 'lib/immutable/_core.rb', line 1058 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.
1453 1454 1455 1456 1457 |
# File 'lib/immutable/_core.rb', line 1453 def map return enum_for(:map) if not block_given? return self if empty? self.class.new(super) end |
#marshal_dump ⇒ ::Array
2275 2276 2277 |
# File 'lib/immutable/_core.rb', line 2275 def marshal_dump to_a end |
#marshal_load(array) ⇒ Object
2280 2281 2282 |
# File 'lib/immutable/_core.rb', line 2280 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.
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 |
# File 'lib/immutable/_core.rb', line 1897 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.
1352 1353 1354 1355 |
# File 'lib/immutable/_core.rb', line 1352 def pop return self if @size == 0 replace_suffix(@size-1, []) end |
#product(*vectors) ⇒ Vector #product ⇒ Vector
Cartesian product or multiplication.
1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 |
# File 'lib/immutable/_core.rb', line 1994 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).
2226 2227 2228 2229 2230 2231 2232 |
# File 'lib/immutable/_core.rb', line 2226 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.
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 |
# File 'lib/immutable/_core.rb', line 1847 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.
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 |
# File 'lib/immutable/_core.rb', line 1951 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.
1509 1510 1511 |
# File 'lib/immutable/_core.rb', line 1509 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.
1411 1412 1413 1414 1415 |
# File 'lib/immutable/_core.rb', line 1411 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.
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 |
# File 'lib/immutable/_core.rb', line 2179 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.
1526 1527 1528 1529 |
# File 'lib/immutable/_core.rb', line 1526 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.
2141 2142 2143 |
# File 'lib/immutable/_core.rb', line 2141 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.
1426 1427 1428 1429 |
# File 'lib/immutable/_core.rb', line 1426 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.
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 |
# File 'lib/immutable/_core.rb', line 1102 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.
1377 1378 1379 |
# File 'lib/immutable/_core.rb', line 1377 def shift delete_at(0) end |
#shuffle ⇒ Vector
Return a new Vector with the same elements as this one, but randomly permuted.
1480 1481 1482 |
# File 'lib/immutable/_core.rb', line 1480 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.
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 |
# File 'lib/immutable/_core.rb', line 1277 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.
1629 1630 1631 |
# File 'lib/immutable/_core.rb', line 1629 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 (‘#<=>`).
1645 1646 1647 |
# File 'lib/immutable/_core.rb', line 1645 def sort_by self.class.new(super) end |
#take(n) ⇒ Vector
Return only the first n elements in a new Vector.
1673 1674 1675 1676 |
# File 'lib/immutable/_core.rb', line 1673 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.
1701 1702 1703 1704 |
# File 'lib/immutable/_core.rb', line 1701 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.
2238 2239 2240 2241 2242 2243 2244 2245 2246 |
# File 'lib/immutable/_core.rb', line 2238 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.
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 |
# File 'lib/immutable/_core.rb', line 2054 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.
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 |
# File 'lib/immutable/_core.rb', line 1492 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.
1366 1367 1368 |
# File 'lib/immutable/_core.rb', line 1366 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.
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 |
# File 'lib/immutable/_core.rb', line 1135 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.
2155 2156 2157 |
# File 'lib/immutable/_core.rb', line 2155 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.
1600 1601 1602 1603 1604 1605 1606 |
# File 'lib/immutable/_core.rb', line 1600 def zip(*others) if block_given? super else self.class.new(super) end end |