Skip to content

Instantly share code, notes, and snippets.

@kch
Last active December 31, 2023 10:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kch/d48568ee224415a0904e1d21830dd436 to your computer and use it in GitHub Desktop.
Save kch/d48568ee224415a0904e1d21830dd436 to your computer and use it in GitHub Desktop.
ruby scanl
# Operating with plain arrays:
class Array
def scanl(init, &f)
return [init] if empty?
reduce([init]){ |xs, x| xs << f.(xs.last, x) }
end
def scanl1(&f)
return if empty? # might consider returning []
drop(1).scanl first, &f
end
end
# Generalized to `Enumerable`, returning `Enumerator`s:
module Enumerable
def self._scanl(enum, a, &f)
Enumerator.new do |y|
y << a
loop { b = enum.next; y << (a = f.(a, b)) }
end
end
def scanl(a, &f)
Enumerable._scanl(each_entry, a, &f)
end
def scanl1(&f)
enum = each_entry
init = enum.next rescue return # might consider returning [].each_entry
Enumerable._scanl(enum, init, &f)
end
def scanr(a, &f)
Enumerable._scanl(each_entry.reverse_each, a, &f).reverse_each
end
def scanr1(&f)
enum = each_entry.reverse_each
init = enum.next rescue return # might consider returning [].each_entry
Enumerable._scanl(enum, init, &f).reverse_each
end
end
# pocket version
module Enumerable
def self._scanl(enum, a, &f)= Enumerator.new {|y| y << a; loop { b = enum.next; y << (a = f.(a, b)) }}
def scanl(a, &f) = Enumerable._scanl(each_entry, a, &f)
def scanl1(&f) = Enumerable._scanl((e=each_entry), (e.next rescue return), &f)
def scanr(a, &f) = Enumerable._scanl(each_entry.reverse_each, a, &f).reverse_each
def scanr1(&f) = Enumerable._scanl((e=each_entry.reverse_each), (e.next rescue return), &f).reverse_each
end
# Examples:
[5].scanl(4) {|*a| a.max }&.to_a # => [4, 5]
[1,2].scanl(4) {|*a| a.max }&.to_a # => [4, 4, 4]
[1,2,3,5,3,7].scanl(4) {|*a| a.max }&.to_a # => [4, 4, 4, 4, 5, 5, 7]
[].scanl1(&:+)&.to_a # => nil
[1].scanl1(&:+)&.to_a # => [1]
[1,2].scanl1(&:+)&.to_a # => [1, 3]
[1,2,3,4].scanl1(&:+)&.to_a # => [1, 3, 6, 10]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment