Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Define length methods for various iterators, using Inf as length for infinite iterators #11977

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export
AbstractSparseVector,
AbstractVector,
AbstractVecOrMat,
AlephNull,
Array,
Associative,
Bidiagonal,
Expand Down Expand Up @@ -198,6 +199,7 @@ export
catalan,
φ, golden,
I,
ℵ₀,

# Operators
!,
Expand Down
39 changes: 39 additions & 0 deletions base/iterator.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# This file is a part of Julia. License is MIT: http://julialang.org/license

# For unbounded length iterators
immutable AlephNull <: Number
end

show(io::IO, ::AlephNull) = print(io, "ℵ₀")
const ℵ₀ = AlephNull()

==(::Integer,::AlephNull) = false
==(::AlephNull,::Integer) = false
==(::AlephNull,::AlephNull) = true

<(::Integer,::AlephNull) = true
<(::AlephNull,::Integer) = false
<(::AlephNull,::AlephNull) = false

<=(::Integer,::AlephNull) = true
<=(::AlephNull,::Integer) = false
<=(::AlephNull,::AlephNull) = true

min(x::Integer, ::AlephNull) = x
min(::AlephNull, x::Integer) = x
min(::AlephNull, ::AlephNull) = AlephNull()

max(::Integer, ::AlephNull) = AlephNull()
max(::AlephNull, ::Integer) = AlephNull()
max(::AlephNull, ::AlephNull) = AlephNull()

+(::Integer, ::AlephNull) = AlephNull()
+(::AlephNull, ::Integer) = AlephNull()
+(::AlephNull, ::AlephNull) = AlephNull()

-(::AlephNull, ::Integer) = AlephNull()

isempty(itr) = done(itr, start(itr))

# enumerate
Expand Down Expand Up @@ -120,6 +153,7 @@ countfrom(start::Number) = Count(start, one(start))
countfrom() = Count(1, 1)

eltype{S}(it::Count{S}) = S
length(it::Count) = AlephNull()

start(it::Count) = it.start
next(it::Count, state) = (state, state + it.step)
Expand All @@ -134,6 +168,7 @@ end
take(xs, n::Int) = Take(xs, n)

eltype(it::Take) = eltype(it.xs)
length(it::Take) = min(length(it.xs), it.n)

start(it::Take) = (it.n, start(it.xs))

Expand All @@ -157,6 +192,7 @@ end
drop(xs, n::Int) = Drop(xs, n)

eltype(it::Drop) = eltype(it.xs)
length(it::Drop) = max(length(it.xs)-it.n, 0)

function start(it::Drop)
xs_state = start(it.xs)
Expand All @@ -181,6 +217,7 @@ end
cycle(xs) = Cycle(xs)

eltype(it::Cycle) = eltype(it.xs)
length(it::Cycle) = AlephNull()

function start(it::Cycle)
s = start(it.xs)
Expand All @@ -205,6 +242,8 @@ immutable Repeated{O}
end
repeated(x) = Repeated(x)
eltype{O}(r::Repeated{O}) = O
length(x::Repeated) = AlephNull()

start(it::Repeated) = nothing
next(it::Repeated, state) = (it.x, nothing)
done(it::Repeated, state) = false
Expand Down
14 changes: 14 additions & 0 deletions doc/stdlib/collections.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ General Collections

For ordered, indexable collections, the maximum index ``i`` for which ``getindex(collection, i)`` is valid. For unordered collections, the number of elements.

If the collection is infinite (e.g. :func:`repeated`), then the function returns ``ℵ₀``, an instance of the singleton type :obj:`AlephNull`.

.. function:: AlephNull()

A singleton type with instance ``ℵ₀`` representing the cardinality of the set of natural numbers. Its main purpose is to provide a well-defined :func:`length` of infinite iterators, and its use outside this context is discouraged.

.. doctest::

julia> length(repeated(1))
ℵ₀

julia> min(ℵ₀,5)
5

.. function:: endof(collection) -> Integer

Returns the last index of the collection.
Expand Down
24 changes: 24 additions & 0 deletions test/functional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ let b = IOBuffer("1\n2\n3\n"), a = []
end
@test a == [(1,"1\n"),(2,"2\n"),(3,"3\n")]
end
@test length(enumerate(1:3)) == 3
@test length(repeated(0)) == ℵ₀


# zip eachline (issue #7369)
let zeb = IOBuffer("1\n2\n3\n4\n5\n"),
Expand All @@ -58,6 +61,9 @@ let zeb = IOBuffer("1\n2\n3\n4\n5\n"),
push!(res, (parse(Int,strip(number)), letter))
end
@test res == [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
@test length(zip(letters, 1:10)) == 5
@test length(zip(letters, countfrom(1))) == 5
@test length(zip(letters, 1:3)) == 3
end

# rest
Expand All @@ -67,6 +73,8 @@ let s = "hello"
@test collect(rest(s, st)) == ['e','l','l','o']
end



# countfrom
# ---------

Expand All @@ -77,6 +85,8 @@ let i = 0
i <= 10 || break
end
end
@test length(countfrom(0,2)) == ℵ₀
@test length(countfrom(0)) == ℵ₀

# take
# ----
Expand All @@ -99,6 +109,10 @@ let i = 0
@test i == 10
end

@test length(take(1:10,5)) == 5
@test length(take(1:10,15)) == 10
@test length(take(countfrom(1),5)) == 5

# drop
# ----

Expand All @@ -110,6 +124,11 @@ let i = 0
@test i == 4
end

@test length(drop(1:10,5)) == 5
@test length(drop(1:10,15)) == 0
@test length(drop(countfrom(0),5)) == ℵ₀


# cycle
# -----

Expand All @@ -121,6 +140,8 @@ let i = 0
end
end

@test length(cycle(0:3)) == ℵ₀

# repeated
# --------

Expand All @@ -138,3 +159,6 @@ let i = 0
i <= 10 || break
end
end

@test length(repeated(1)) == ℵ₀
@test length(repeated(1,10)) == 10