Indexable(T) - Crystal 0.35.1

# module Indexable(T)

##
Overview

A container that allows accessing elements via a numeric index.

Indexing starts at `0`. A negative index is assumed to be relative to the end of the container: `-1` indicates the last element, `-2` is the next to last element, and so on.

Types including this module are typically `Array`-like types.

##
Included Modules

- Enumerable(T)
- Iterable(T)

##
Direct including types

- Array(T)
- BitArray
- Deque(T)
- LLVM::ParameterCollection
- Slice(T)
- StaticArray(T, N)
- Tuple(*T)

##
Defined in:

##
Instance Method Summary

- #[](index : Int)

  Returns the element at the given index.

- #[]?(index : Int)

  Returns the element at the given index.

- #bsearch(&block : T -> Bool)

  By using binary search, returns the first element for which the passed block returns `true`.

- #bsearch_index(&block : T, Int32 -> Bool)

  By using binary search, returns the index of the first element for which the passed block returns `true`.

- #dig(index : Int, *subindexes)

  Traverses the depth of a structure and returns the value, otherwise raises `IndexError`.

- #dig?(index : Int, *subindexes)

  Traverses the depth of a structure and returns the value.

- #each

  Returns an `Iterator` for the elements of `self`.

- #each(*, within range : Range, &)

  Calls the given block once for all elements at indices within the given `range`, passing each element as a parameter.

- #each(&)

  Calls the given block once for each element in `self`, passing that element as a parameter.

- #each(*, start : Int, count : Int, &)

  Calls the given block once for `count` number of elements in `self` starting from index `start`, passing each element as a parameter.

- #each_index(*, start : Int, count : Int, &)

  Calls the given block once for `count` number of indices in `self` starting from index `start`, passing each index as a parameter.

- #each_index(&) : Nil

  Calls the given block once for each index in `self`, passing that index as a parameter.

- #each_index

  Returns an `Iterator` for each index in `self`.

- #empty?

  Returns `true` if `self` is empty, `false` otherwise.

- #equals?(other : Indexable, &)

  Optimized version of `#equals?` used when `other` is also an `Indexable`.

- #equals?(other, &)

  Determines if `self` equals other according to a comparison done by the given block.

- #fetch(index, default)

  Returns the value at the index given by index, or when not found the value given by default.

- #fetch(index : Int, &)

  Returns the element at the given index, if in bounds, otherwise executes the given block with the index and returns its value.

- #first(&)

  :inherited:

- #hash(hasher)

  See `Object#hash(hasher)`

- #index(object, offset : Int = 0)

  Returns the index of the first appearance of value in `self` starting from the given offset, or `nil` if the value is not in `self`.

- #index(offset : Int = 0, &)

  Returns the index of the first object in `self` for which the block returns `true`, starting from the given offset, or `nil` if no match is found.

- #join(separator = "")

  Optimized version of `Enumerable#join` that performs better when all of the elements in this indexable are strings: the total string bytesize to return can be computed before creating the final string, which performs better because there's no need to do reallocations.

- #last

  Returns the last element of `self` if it's not empty, or raises `IndexError`.

- #last(&)

  Returns the last element of `self` if it's not empty, or the given block's value.

- #last?

  Returns the last element of `self` if it's not empty, or `nil`.

- #reverse_each(&) : Nil

  Same as `#each`, but works in reverse.

- #reverse_each

  Returns an `Iterator` over the elements of `self` in reverse order.

- #rindex(value, offset = size - 1)

  Returns the index of the last appearance of value in `self`, or `nil` if the value is not in `self`.

- #rindex(offset = size - 1, &)

  Returns the index of the first object in `self` for which the block returns `true`, starting from the last object, or `nil` if no match is found.

- #sample(random = Random::DEFAULT)

  Returns a random element from `self`, using the given random number generator.

- #size

  Returns the number of elements in this container.

- #to_a

  Returns an `Array` with all the elements in the collection.

- #unsafe_fetch(index : Int)

  Returns the element at the given index, without doing any bounds check.

- #values_at(*indexes : Int)

  Returns a `Tuple` populated with the elements at the given indexes.

### Instance methods inherited from module `Enumerable(T)`

all?(&)
all?(pattern)
all? all?, any?(&)
any?(pattern)
any? any?, chunks(&block : T -> U) forall U chunks, compact_map(&) compact_map, count(&)
count(item) count, cycle(&)
cycle(n, &) cycle, each(&block : T -> _) each, each_cons(count : Int, reuse = false, &) each_cons, each_cons_pair(& : T, T -> _) : Nil each_cons_pair, each_slice(count : Int, reuse = false, &) each_slice, each_with_index(offset = 0, &) each_with_index, each_with_object(obj, &) each_with_object, empty? empty?, find(if_none = nil, &) find, first(&)
first(count : Int)
first first, first? first?, flat_map(&block : T -> Array(U) | Iterator(U) | U) forall U flat_map, grep(pattern) grep, group_by(&block : T -> U) forall U group_by, in_groups_of(size : Int, filled_up_with : U = nil) forall U
in_groups_of(size : Int, filled_up_with : U = nil, reuse = false, &) forall U in_groups_of, includes?(obj) includes?, index(&)
index(obj) index, index_by(&block : T -> U) forall U index_by, join(separator = "", & : T -> )
join(separator, io : IO, &)
join(io : IO, separator = "", & : T, IO -> )
join(separator = "")
join(separator, io : IO)
join(io : IO, separator = "") join, map(&block : T -> U) forall U map, map_with_index(offset = 0, &block : T, Int32 -> U) forall U map_with_index, max max, max? max?, max_by(&block : T -> U) forall U max_by, max_by?(&block : T -> U) forall U max_by?, max_of(&block : T -> U) forall U max_of, max_of?(&block : T -> U) forall U max_of?, min min, min? min?, min_by(&block : T -> U) forall U min_by, min_by?(&block : T -> U) forall U min_by?, min_of(&block : T -> U) forall U min_of, min_of?(&block : T -> U) forall U min_of?, minmax minmax, minmax? minmax?, minmax_by(&block : T -> U) forall U minmax_by, minmax_by?(&block : T -> U) forall U minmax_by?, minmax_of(&block : T -> U) forall U minmax_of, minmax_of?(&block : T -> U) forall U minmax_of?, none?
none?(pattern)
none?(&) none?, one?(&)
one?(pattern)
one? one?, partition(&) partition, product
product(initial : Number)
product(initial : Number, &)
product(&) product, reduce(memo, &)
reduce(&) reduce, reduce?(&) reduce?, reject(pattern)
reject(type : U.class) forall U
reject(&block : T -> ) reject, select(pattern)
select(type : U.class) forall U
select(&block : T -> ) select, size size, skip(count : Int) skip, skip_while(&) skip_while, sum(initial)
sum
sum(initial, &)
sum(&) sum, take_while(&) take_while, tally : Hash(T, Int32) tally, to_a to_a, to_h
to_h(&block : T -> Tuple(K, V)) forall K, V to_h, to_set to_set, zip(*others : Indexable | Iterable | Iterator, &)
zip(*others : Indexable | Iterable | Iterator) zip, zip?(*others : Indexable | Iterable | Iterator, &)
zip?(*others : Indexable | Iterable | Iterator) zip?

### Instance methods inherited from module `Iterable(T)`

chunk(reuse = false, &block : T -> U) forall U chunk, chunk_while(reuse : Bool | Array(T) = false, &block : T, T -> B) forall B chunk_while, cycle(n)
cycle cycle, each each, each_cons(count : Int, reuse = false) each_cons, each_slice(count : Int, reuse = false) each_slice, each_with_index(offset = 0) each_with_index, each_with_object(obj) each_with_object, slice_after(reuse : Bool | Array(T) = false, &block : T -> B) forall B
slice_after(pattern, reuse : Bool | Array(T) = false) slice_after, slice_before(reuse : Bool | Array(T) = false, &block : T -> B) forall B
slice_before(pattern, reuse : Bool | Array(T) = false) slice_before, slice_when(reuse : Bool | Array(T) = false, &block : T, T -> B) forall B slice_when

##
Instance Method Detail

def [](index : Int) #

Returns the element at the given index.

Negative indices can be used to start counting from the end of the array. Raises `IndexError` if trying to access an element outside the array's range.

    ary = ['a', 'b', 'c']
    ary[0]  # => 'a'
    ary[2]  # => 'c'
    ary[-1] # => 'c'
    ary[-2] # => 'b'

    ary[3]  # raises IndexError
    ary[-4] # raises IndexError

def []?(index : Int) #

Returns the element at the given index.

Negative indices can be used to start counting from the end of the array. Returns `nil` if trying to access an element outside the array's range.

    ary = ['a', 'b', 'c']
    ary[0]?  # => 'a'
    ary[2]?  # => 'c'
    ary[-1]? # => 'c'
    ary[-2]? # => 'b'

    ary[3]?  # nil
    ary[-4]? # nil

def bsearch(&block : T -> Bool) #

By using binary search, returns the first element for which the passed block returns `true`.

If the block returns `false`, the finding element exists behind. If the block returns `true`, the finding element is itself or exists infront.

Binary search needs sorted array, so `self` has to be sorted.

Returns `nil` if the block didn't return `true` for any element.

    [2, 5, 7, 10].bsearch { |x| x >= 4 } # => 5
    [2, 5, 7, 10].bsearch { |x| x > 10 } # => nil

def bsearch_index(&block : T, Int32 -> Bool) #

By using binary search, returns the index of the first element for which the passed block returns `true`.

If the block returns `false`, the finding element exists behind. If the block returns `true`, the finding element is itself or exists infront.

Binary search needs sorted array, so `self` has to be sorted.

Returns `nil` if the block didn't return `true` for any element.

    [2, 5, 7, 10].bsearch_index { |x, i| x >= 4 } # => 1
    [2, 5, 7, 10].bsearch_index { |x, i| x > 10 } # => nil

def dig(index : Int, *subindexes) #

Traverses the depth of a structure and returns the value, otherwise raises `IndexError`.

    ary = [{1, 2, 3, {4, 5, 6}}]
    ary.dig(0, 3, 2) # => 6
    ary.dig(0, 3, 3) # raises IndexError

def dig?(index : Int, *subindexes) #

Traverses the depth of a structure and returns the value. Returns `nil` if not found.

    ary = [{1, 2, 3, {4, 5, 6}}]
    ary.dig?(0, 3, 2) # => 6
    ary.dig?(0, 3, 3) # => nil

def each #

Returns an `Iterator` for the elements of `self`.

    a = ["a", "b", "c"]
    iter = a.each
    iter.next # => "a"
    iter.next # => "b"

The returned iterator keeps a reference to `self`: if the array changes, the returned values of the iterator change as well.

def each(*, within range : Range, &) #

Calls the given block once for all elements at indices within the given `range`, passing each element as a parameter.

Raises `IndexError` if the starting index is out of range.

    array = ["a", "b", "c", "d", "e"]
    array.each(within: 1..3) { |x| print x, " -- " }

produces:

    b -- c -- d --

def each(&) #

Calls the given block once for each element in `self`, passing that element as a parameter.

    a = ["a", "b", "c"]
    a.each { |x| print x, " -- " }

produces:

    a -- b -- c --

def each(*, start : Int, count : Int, &) #

Calls the given block once for `count` number of elements in `self` starting from index `start`, passing each element as a parameter.

Negative indices count backward from the end of the array. (-1 is the last element).

Raises `IndexError` if the starting index is out of range. Raises `ArgumentError` if `count` is a negative number.

    array = ["a", "b", "c", "d", "e"]
    array.each(start: 1, count: 3) { |x| print x, " -- " }

produces:

    b -- c -- d --

def each_index(*, start : Int, count : Int, &) #

Calls the given block once for `count` number of indices in `self` starting from index `start`, passing each index as a parameter.

Negative indices count backward from the end of the array. (-1 is the last element).

Raises `IndexError` if the starting index is out of range. Raises `ArgumentError` if `count` is a negative number.

    array = ["a", "b", "c", "d", "e"]
    array.each_index(start: -3, count: 2) { |x| print x, " -- " }

produces:

    2 -- 3 --

def each_index(&) : Nil #

Calls the given block once for each index in `self`, passing that index as a parameter.

    a = ["a", "b", "c"]
    a.each_index { |x| print x, " -- " }

produces:

    0 -- 1 -- 2 --

def each_index #

Returns an `Iterator` for each index in `self`.

    a = ["a", "b", "c"]
    iter = a.each_index
    iter.next # => 0
    iter.next # => 1

The returned iterator keeps a reference to `self`. If the array changes, the returned values of the iterator will change as well.

def empty? #

Returns `true` if `self` is empty, `false` otherwise.

    ([] of Int32).empty? # => true
    ([1]).empty?         # => false

def equals?(other : Indexable, &) #

Optimized version of `#equals?` used when `other` is also an `Indexable`.

def equals?(other, &) #

Determines if `self` equals other according to a comparison done by the given block.

If `self`'s size is the same as other's size, this method yields elements from `self` and other in tandem: if the block returns true for all of them, this method returns `true`. Otherwise it returns `false`.

    a = [1, 2, 3]
    b = ["a", "ab", "abc"]
    a.equals?(b) { |x, y| x == y.size } # => true
    a.equals?(b) { |x, y| x == y }      # => false

def fetch(index, default) #

Returns the value at the index given by index, or when not found the value given by default.

    a = [:foo, :bar]
    a.fetch(0, :default_value) # => :foo
    a.fetch(2, :default_value) # => :default_value

def fetch(index : Int, &) #

Returns the element at the given index, if in bounds, otherwise executes the given block with the index and returns its value.

    a = [:foo, :bar]
    a.fetch(0) { :default_value }    # => :foo
    a.fetch(2) { :default_value }    # => :default_value
    a.fetch(2) { |index| index * 3 } # => 6

def first(&) #

:inherited:

def hash(hasher) #

See `Object#hash(hasher)`

def index(object, offset : Int = 0) #

Returns the index of the first appearance of value in `self` starting from the given offset, or `nil` if the value is not in `self`.

    [1, 2, 3, 1, 2, 3].index(2, offset: 2) # => 4

def index(offset : Int = 0, &) #

Returns the index of the first object in `self` for which the block returns `true`, starting from the given offset, or `nil` if no match is found.

    [1, 2, 3, 1, 2, 3].index(offset: 2) { |x| x < 2 } # => 3

def join(separator = "") #

Optimized version of `Enumerable#join` that performs better when all of the elements in this indexable are strings: the total string bytesize to return can be computed before creating the final string, which performs better because there's no need to do reallocations.

def last #

Returns the last element of `self` if it's not empty, or raises `IndexError`.

    ([1, 2, 3]).last   # => 3
    ([] of Int32).last # raises IndexError

def last(&) #

Returns the last element of `self` if it's not empty, or the given block's value.

    ([1, 2, 3]).last { 4 }   # => 3
    ([] of Int32).last { 4 } # => 4

def last? #

Returns the last element of `self` if it's not empty, or `nil`.

    ([1, 2, 3]).last?   # => 3
    ([] of Int32).last? # => nil

def reverse_each(&) : Nil #

Same as `#each`, but works in reverse.

def reverse_each #

Returns an `Iterator` over the elements of `self` in reverse order.

def rindex(value, offset = size - 1) #

Returns the index of the last appearance of value in `self`, or `nil` if the value is not in `self`.

If offset is given, it defines the position to end the search (elements beyond this point are ignored).

    [1, 2, 3, 2, 3].rindex(2)            # => 3
    [1, 2, 3, 2, 3].rindex(2, offset: 2) # => 1

def rindex(offset = size - 1, &) #

Returns the index of the first object in `self` for which the block returns `true`, starting from the last object, or `nil` if no match is found.

If offset is given, the search starts from that index towards the first elements in `self`.

    [1, 2, 3, 2, 3].rindex { |x| x < 3 }            # => 3
    [1, 2, 3, 2, 3].rindex(offset: 2) { |x| x < 3 } # => 1

def sample(random = Random::DEFAULT) #

Returns a random element from `self`, using the given random number generator. Raises `IndexError` if `self` is empty.

    a = [1, 2, 3]
    a.sample                # => 2
    a.sample                # => 1
    a.sample(Random.new(1)) # => 3

abstract def size #

Returns the number of elements in this container.

def to_a #

Returns an `Array` with all the elements in the collection.

    {1, 2, 3}.to_a # => [1, 2, 3]

abstract def unsafe_fetch(index : Int) #

Returns the element at the given index, without doing any bounds check.

`Indexable` makes sure to invoke this method with index in `0...size`, so converting negative indices to positive ones is not needed here.

Clients never invoke this method directly. Instead, they access elements with `#[](index)` and `#[]?(index)`.

This method should only be directly invoked if you are absolutely sure the index is in bounds, to avoid a bounds check for a small boost of performance.

def values_at(*indexes : Int) #

Returns a `Tuple` populated with the elements at the given indexes. Raises `IndexError` if any index is invalid.

    ["a", "b", "c", "d"].values_at(0, 2) # => {"a", "c"}