NAME
Sidef::Object::Enumerator
DESCRIPTION
This class implements an enumerator object, allowing for functional-style operations such as mapping, filtering, and accessing elements within a collection. The enumerator is designed with lazy evaluation in mind, making it suitable for working with potentially infinite sequences.
An enumerator is created with a block that receives a callback function. The block calls this callback for each element it wants to yield. This enables the creation of custom iterators and generators.
SYNOPSIS
# Create an enumerator that yields prime numbers
var primes = Enumerator({ |yield|
for n in (2.. Inf) {
yield(n) if n.is_prime
}
})
# Get the first 10 primes
say primes.first(10) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
# Create a Fibonacci sequence enumerator
var fib = Enumerator({ |yield|
var (a, b) = (0, 1)
loop {
yield(a)
(a, b) = (b, a + b)
}
})
say fib.first(10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
METHODS
new
Enumerator(block)
self. new
Creates a new enumerator instance with the given block. The block receives a callback function (commonly named yield or f or cb) that should be called for each element the enumerator produces.
var squares = Enumerator({ |yield|
for n in (1.. Inf) {
yield(n * n)
}
})
Aliases: call
count
self.count(block)
Counts and returns the number of elements in the enumerator collection that satisfy the given block condition.
var e = Enumerator({ |f| 1.. 100 -> each { |i| f(i) } })
say e.count { . is_prime } # 25
Note: This method consumes the entire enumerator.
Aliases: count_by
each
self.each(block)
Iterates over all elements in the enumerator, passing each element to the given block. Returns the enumerator itself.
var e = Enumerator({ |f| 1..5 -> each { |i| f(i) } })
e.each { |n| say n } # prints 1, 2, 3, 4, 5
Warning: Do not use on infinite enumerators as it will loop forever.
first
self.first(n)
self.first(n, block)
Returns the first n elements of the enumerator as an array. If a block is provided, it retrieves the first n elements that satisfy the block condition.
var e = Enumerator({ |f| 1.. Inf -> each { |i| f(i) } })
say e.first(5) # [1, 2, 3, 4, 5]
say e.first(5, { . is_prime }) # [2, 3, 5, 7, 11]
grep
self.grep(block)
Filters the elements in the enumerator collection based on the given block condition. Returns a new array containing only the elements for which the block returns a true value.
var e = Enumerator({ |f| 1..20 -> each { |i| f(i) } })
say e.grep { .is_even } # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Note: This method consumes the entire enumerator.
Aliases: select
len
self.len
Returns the total number of elements in the enumerator by consuming all elements and counting them.
var e = Enumerator({ |f| 1..100 -> each { |i| f(i) if i.is_prime } })
say e.len # 25
Warning: Do not use on infinite enumerators as it will loop forever.
Aliases: size, length
map
self.map(block)
Applies the given block to each element of the enumerator and returns a new array with the transformed elements.
var e = Enumerator({ |f| 1..5 -> each { |i| f(i) } })
say e.map { _ * 2 } # [2, 4, 6, 8, 10]
Note: This method consumes the entire enumerator.
Aliases: collect
nth
e.nth(n)
e.nth(n, block)
Retrieves the n-th element from the enumerator collection (1-indexed). If an optional block is provided, it counts only the elements for which the block returns a true value, returning the n-th matching element.
var e = Enumerator({ |f| 1.. Inf -> each { |i| f(i) } })
say e.nth(10) # 10
say e. nth(10, { .is_prime }) # 29 (the 10th prime number)
to_a
self.to_a
Converts the enumerator into an array by consuming all elements and collecting them. Returns the resulting array.
var e = Enumerator({ |f| 1..5 -> each { |i| f(i) } })
say e.to_a # [1, 2, 3, 4, 5]
Warning: Do not use on infinite enumerators as it will loop forever.
while
self.while(block)
Yields elements to the given block and collects them into an array until the block returns false. Stops iterating immediately when the block returns a false value.
var palindromes = Enumerator({ |f|
var n = 1
loop { f(n); n. next_palindrome! }
})
# Get all palindromes less than 100
say palindromes. while { _ < 100 }
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99]
This method is particularly useful for working with infinite enumerators when you want to collect elements up to a certain condition.
EXAMPLES
Ludic Numbers
func ludics_upto(nmax = 100000) {
Enumerator({ |collect|
collect(1)
var arr = @(2.. nmax)
while (arr) {
collect(var n = arr[0])
arr. range. by(n).each { |i| arr[i] = nil }
arr. compact!
}
})
}
say ludics_upto(1000).first(25)
Infinite Prime Generator
var primes = Enumerator({ |yield|
for n in (2..Inf) {
yield(n) if n.is_prime
}
})
say primes.first(10) # First 10 primes
say primes.nth(100) # The 100th prime
say primes. first(20, {_ > 50}) # First 20 primes greater than 50
Word Wrapping
func wordwrap(words, maxwidth) {
Enumerator({ |y|
var cols = 0
words.slice_before { |w|
cols += 1 if (cols != 0)
cols += w.len
if (maxwidth < cols) {
cols = w.len
true
} else {
false
}
}. each { |ws| y(ws) }
})
}
var text = "The quick brown fox jumps over the lazy dog"
wordwrap(text. words, 15).each { |line| say line. join(" ") }
SEE ALSO
Sidef::Types::Array::Array, Sidef::Types::Range::RangeNumber