NAME

Sidef::Types::Range::Range - Range class for representing sequences of values

DESCRIPTION

The Range class implements a lazy sequence of values between two endpoints. Ranges are memory-efficient as they don't store all values but generate them on demand. They support arithmetic operations, iteration, and functional programming methods.

A range can be created using the range operator .. or by calling the Range constructor. Ranges are commonly used in loops, array slicing, and generating sequences.

SYNOPSIS

# Create a range from 1 to 10
var r = (1..10)

# Iterate over range
(1..10).each { |n|
    say n
}

# Range with custom step
var evens = (0..20 `by` 2)

# Infinite ranges
var infinite = (1..Inf)

# Map over a range
var squares = (1..5).map { |n| n**2 }

# Filter range values
var odds = (1..20).grep { .is_odd }

# Range arithmetic
var r1 = (1..5)
var r2 = (10..15)
say (r1 + r2)  # Add ranges

METHODS

*

a * b

Multiplies the range by a scalar value or another range. When multiplying by a scalar, each element in the range is multiplied. When multiplying by another range, performs element-wise multiplication.

say ((1..5) * 2)      #=> Range(2, 4, 6, 8, 10)
say ((1..3) * (2..4)) #=> Range(2, 6, 12)

Aliases: mul

+

a + b

Adds a scalar value or another range to the range. When adding a scalar, adds it to each element. When adding another range, performs element-wise addition.

say ((1..5) + 10)     #=> Range(11, 12, 13, 14, 15)
say ((1..3) + (5..7)) #=> Range(6, 8, 10)

Aliases: add

-

a - b

Subtracts a scalar value or another range from the range. When subtracting a scalar, subtracts it from each element. When subtracting another range, performs element-wise subtraction.

say ((10..15) - 5)    #=> Range(5, 6, 7, 8, 9, 10)
say ((10..12) - (1..3)) #=> Range(9, 10, 11)

Aliases: sub

...

a ... b

Converts the range to a list (array) containing all values in the range. This forces evaluation of the lazy range.

var arr = (1..5)...
say arr  #=> [1, 2, 3, 4, 5]

Aliases: to_list

/

a / b

Divides the range by a scalar value or another range. When dividing by a scalar, divides each element. When dividing by another range, performs element-wise division.

say ((10..20 `by` 5) / 2)  #=> Range(5, 7.5, 10)
say ((10..30 `by` 10) / (2..4)) #=> Range(5, 10, 15)

Aliases: ÷, div

==

a == b

Checks if two ranges are equal. Ranges are equal if they have the same bounds, step, and direction.

say ((1..10) == (1..10))  #=> true
say ((1..10) == (1..20))  #=> false
say ((1..10 `by` 2) == (1..10)) #=> false

Aliases: eq

a ≠ b

Checks if two ranges are not equal. Returns true if the ranges differ in bounds, step, or direction.

say ((1..10) ≠ (1..20))  #=> true
say ((1..10) ≠ (1..10))  #=> false

Aliases: !=, ne

accumulate

self.accumulate(block)

Returns an array of accumulated values by applying the given block (or operator) cumulatively. Similar to a running sum or cumulative operation.

say (1..5).accumulate { |a, b| a + b }  #=> [1, 3, 6, 10, 15]
say (1..4).accumulate { |a, b| a * b }  #=> [1, 2, 6, 24]

accumulate_by

self.accumulate_by(block)

Returns an array of accumulated values by applying the given block to each element first, then accumulating.

say (1..5).accumulate_by { |n| n**2 }  #=> [1, 5, 14, 30, 55]

all

self.all(block)

Returns true if all elements in the range satisfy the condition in the block. Returns false otherwise.

say (1..10).all { |n| n > 0 }    #=> true
say (1..10).all { |n| n.is_even } #=> false

any

self.any(block)

Returns true if at least one element in the range satisfies the condition in the block. Returns false if none do.

say (1..10).any { |n| n > 5 }     #=> true
say (1..10).any { |n| n > 20 }    #=> false
say (1..10).any { |n| n.is_even } #=> true

bounds

self.bounds

Returns an array containing the start and end bounds of the range.

say (1..10).bounds    #=> [1, 10]
say (5..1).bounds     #=> [5, 1]
say (0..100 `by` 5).bounds  #=> [0, 100]

by

self.by(step)

Creates a new range with the specified step size. This allows you to skip values in the sequence.

say (1..10 `by` 2)...    #=> [1, 3, 5, 7, 9]
say (0..20 `by` 5)...    #=> [0, 5, 10, 15, 20]
say (10..1 `by` -2)...   #=> [10, 8, 6, 4, 2]

cons

self.cons(n, block)

Maps over consecutive groups of n elements from the range. Returns an array of results from applying the block to each consecutive group.

say (1..10).cons(3) { |*group| group.sum }  #=> [6, 9, 12, 15, 18, 21, 24, 27]

Aliases: map_cons

contain

self.contain(value)

Checks if the range contains the specified value. Takes into account the range's bounds, step, and direction.

say (1..10).contain(5)        #=> true
say (1..10).contain(15)       #=> false
say (1..10 `by` 2).contain(3) #=> false
say (1..10 `by` 2).contain(5) #=> true

Aliases: include, contains, includes

count

self.count(arg)

Counts elements in the range that match the given value or satisfy the given block condition.

say (1..10).count(5)            #=> 1
say (1..10).count { |n| n.is_even }  #=> 5
say (1..20).count { |n| n.is_prime } #=> 8

count_by

self.count_by(block)

Returns a hash with counts of elements grouped by the result of applying the block to each element.

say (1..10).count_by { |n| n % 3 }
#=> Hash(0 => 3, 1 => 4, 2 => 3)

say (1..10).count_by { |n| n.is_even ? "even" : "odd" }
#=> Hash("even" => 5, "odd" => 5)

cross_operator

self.cross_operator(*args)

Performs a cross product operation with other ranges or arrays, applying an operator to combinations.

say (1..3).cross_operator('+', 10..12)
#=> [[11, 12, 13], [12, 13, 14], [13, 14, 15]]

each_cons

self.each_cons(n, block)

Iterates over consecutive groups of n elements, passing each group to the block. Similar to cons but doesn't collect results.

(1..10).each_cons(3) { |*group|
    say group
}
# Prints: [1, 2, 3], [2, 3, 4], [3, 4, 5], ...

each_slice

self.each_slice(n, block)

Iterates over the range in slices of n elements, passing each slice to the block.

(1..10).each_slice(3) { |*slice|
    say slice
}
# Prints: [1, 2, 3], [4, 5, 6], [7, 8, 9], [10]

first_by

self.first_by(block)

Returns the first element for which the block returns true, or nil if no element satisfies the condition.

say (1..100).first_by { |n| n > 50 && n.is_prime }  #=> 53
say (1..10).first_by { |n| n > 100 }  #=> nil

flip

self.flip

Returns a new range with reversed bounds (flips the direction of iteration).

say (1..10).flip...   #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
say (5..1).flip...    #=> [1, 2, 3, 4, 5]

Aliases: reverse

for

self.for(block)

Iterates over each element in the range, passing it to the block. This is the standard iteration method.

(1..5).for { |n|
    say n
}
# Prints: 1, 2, 3, 4, 5

Aliases: each, foreach

from

self.from(from)

Creates a new range starting from the specified value, keeping the original end bound.

say (1..10).from(5)...   #=> [5, 6, 7, 8, 9, 10]

grep

self.grep(block)

Filters the range, returning an array of elements that satisfy the condition in the block.

say (1..20).grep { |n| n.is_prime }  #=> [2, 3, 5, 7, 11, 13, 17, 19]
say (1..10).grep { |n| n > 5 }       #=> [6, 7, 8, 9, 10]

Aliases: select

self.head(num)

Returns an array containing the first num elements of the range.

say (1..100).head(5)   #=> [1, 2, 3, 4, 5]
say (10..1).head(3)    #=> [10, 9, 8]

Aliases: first

join

self.join(sep)

Converts the range to a string with elements joined by the specified separator.

say (1..5).join(', ')    #=> "1, 2, 3, 4, 5"
say (1..3).join(' + ')   #=> "1 + 2 + 3"

kv

self.kv

Returns an array of [index, value] pairs for each element in the range.

say (10..13).kv  #=> [[0, 10], [1, 11], [2, 12], [3, 13]]

Aliases: pairs, zip_indices

last

self.last(num)

Returns an array containing the last num elements of the range.

say (1..10).last(3)   #=> [8, 9, 10]

Aliases: tail

last_by

self.last_by(block)

Returns the last element for which the block returns true, or nil if no element satisfies the condition.

say (1..100).last_by { |n| n < 50 && n.is_prime }  #=> 47
say (1..10).last_by { |n| n > 100 }  #=> nil

len

self.len

Returns the number of elements in the range.

say (1..10).len           #=> 10
say (0..20 `by` 5).len    #=> 5
say (10..1).len           #=> 10

Aliases: length

map

self.map(block)

Transforms each element in the range using the given block, returning an array of results.

say (1..5).map { |n| n**2 }      #=> [1, 4, 9, 16, 25]
say (1..3).map { |n| n * 10 }    #=> [10, 20, 30]

map_operator

self.map_operator(op, *args)

Maps an operator over the range with additional arguments.

say (1..5).map_operator('+', 10)  #=> [11, 12, 13, 14, 15]
say (1..5).map_operator('**', 2)  #=> [1, 4, 9, 16, 25]

max

self.max(block)

Returns the maximum element in the range. With a block, compares elements using the block's return value.

say (1..10).max              #=> 10
say (1..10).max { |a, b| b <=> a }  #=> 1 (reverse order)

max_by

self.max_by(block)

Returns the element that produces the maximum value when passed through the block.

say (-5..5).max_by { |n| n.abs }      #=> -5 or 5
say (1..10).max_by { |n| n % 3 }      #=> 2 (or 5 or 8)

min

self.min(block)

Returns the minimum element in the range. With a block, compares elements using the block's return value.

say (1..10).min              #=> 1
say (1..10).min { |a, b| b <=> a }  #=> 10 (reverse order)

min_by

self.min_by(block)

Returns the element that produces the minimum value when passed through the block.

say (-5..5).min_by { |n| n.abs }      #=> 0
say (1..10).min_by { |n| -n }         #=> 10

neg

self.neg

Returns a new range with all elements negated.

say (1..5).neg...    #=> [-1, -2, -3, -4, -5]
say (-3..3).neg...   #=> [3, 2, 1, 0, -1, -2, -3]

new

Range.new(from, to, step)

Creates a new range object with the specified start, end, and optional step values.

var r1 = Range.new(1, 10)
var r2 = Range.new(0, 20, 2)
var r3 = Range(5, 1, -1)

Aliases: call

none

self.none(block)

Returns true if no elements in the range satisfy the condition in the block.

say (1..10).none { |n| n > 20 }     #=> true
say (1..10).none { |n| n > 5 }      #=> false

pam_operator

self.pam_operator(op, *args)

Applies the pam operator (parallel map) over the range elements.

say (1..5).pam_operator('+', 10)

pick

self.pick(n)

Returns n random elements from the range without replacement. If n is not specified, returns one random element.

say (1..10).pick      #=> (random number from 1 to 10)
say (1..10).pick(3)   #=> [random 3 numbers, e.g., [7, 2, 9]]

rand

self.rand(n)

Returns n random elements from the range with replacement. Each call can return duplicate values.

say (1..10).rand      #=> (random number from 1 to 10)
say (1..10).rand(5)   #=> [5 random numbers, may contain duplicates]

Aliases: sample

reduce

self.reduce(op, initial)

Reduces the range to a single value by applying the given operator or block cumulatively. The initial value is optional.

say (1..5).reduce { |a, b| a + b }      #=> 15
say (1..4).reduce { |a, b| a * b }      #=> 24
say (1..10).reduce('+')                 #=> 55
say (1..5).reduce('+', 100)             #=> 115

reduce_operator

self.reduce_operator(op, initial)

Reduces the range using a named operator. Similar to reduce but takes an operator name as a string.

say (1..10).reduce_operator('+')     #=> 55
say (1..4).reduce_operator('*')      #=> 24

shuffle

self.shuffle

Returns an array with the range elements in random order.

say (1..10).shuffle   #=> [random permutation, e.g., [3, 7, 1, 9, 2, 5, 10, 4, 8, 6]]

slices

self.slices(n, block)

Maps over slices of n elements, applying the block to each slice and returning an array of results.

say (1..10).slices(3) { |*slice| slice.sum }
#=> [6, 15, 24, 10]

Aliases: map_slice

sort

self.sort(block)

Returns a sorted array of the range elements. With a block, uses the block for custom comparison.

say (1..10).sort { |a, b| b <=> a }  #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

sort_by

self.sort_by(block)

Returns an array sorted by the value returned from applying the block to each element.

say (-5..5).sort_by { |n| n.abs }    #=> [0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]
say (1..10).sort_by { |n| -n }       #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

step

self.step

Returns the step size of the range. For ranges created without an explicit step, returns 1 or -1 depending on direction.

say (1..10).step          #=> 1
say (0..20 `by` 5).step   #=> 5
say (10..1).step          #=> -1

to

self.to(to)

Creates a new range with the specified end bound, keeping the original start bound.

say (1..5).to(10)...   #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

to_a

self.to_a

Converts the range to an array containing all its elements. Forces evaluation of the lazy range.

say (1..5).to_a   #=> [1, 2, 3, 4, 5]

Aliases: to_array

to_v

self.to_v

Converts the range to a vector (Vector object).

var vec = (1..5).to_v

Aliases: to_vec, to_vector

unroll_operator

self.unroll_operator(op, *args)

Applies an unroll operator operation over the range.

say (1..5).unroll_operator('+', 10)

while

self.while(block)

Iterates over the range while the block condition is true, returning an array of elements.

say (1..100).while { |n| n < 10 }  #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

zip_operator

self.zip_operator(op, *args)

Zips the range with other ranges or arrays, applying an operator to corresponding elements.

say (1..3).zip_operator('+', 10..12)  #=> [11, 13, 15]

SEE ALSO

Sidef::Types::Array::Array, Sidef::Types::Number::Number

AUTHOR

Daniel Șuteu (trizen)