diff --git a/README.md b/README.md index e0e8de3..5e87dac 100644 --- a/README.md +++ b/README.md @@ -152,9 +152,9 @@ Install this package with `Pkg.add("Iterators")` i = 'c' ``` -- **product**(xs...) +- **product**(xs..., [order]) - Iterate over all combinations in the cartesian product of the inputs. + Iterate over all combinations in the cartesian product of the inputs. The `order` keyword argument specifies whether the elements are traversed in lexicographic order (`false`) or anti-lexicographic order (`true`, the default value). Example: ```julia @@ -171,6 +171,21 @@ Install this package with `Pkg.add("Iterators")` p = (2,2) p = (3,2) ``` + while + ```julia + for p in product(1:3,1:2,order=false) + @show p + end + ``` + yields + ``` + p = (1,1) + p = (1,2) + p = (2,1) + p = (2,2) + p = (3,1) + p = (3,2) + ``` - **distinct**(xs) diff --git a/src/Iterators.jl b/src/Iterators.jl index 0fae7c9..838417e 100644 --- a/src/Iterators.jl +++ b/src/Iterators.jl @@ -19,7 +19,9 @@ export imap, subsets, iterate, - @itr + @itr, + AntiLexicographicOrder, + LexicographicOrder # Infinite counting @@ -258,17 +260,30 @@ done(it::Chain, state) = state[1] > length(it.xss) # Cartesian product as a sequence of tuples -immutable Product +abstract SortingOrder + +abstract LexicographicOrder <: SortingOrder +abstract AntiLexicographicOrder <: SortingOrder + +immutable Product{order} xss::Vector{Any} - function Product(xss...) - new(Any[xss...]) - end + Product(xss...)=new(Any[xss...]) end + eltype(p::Product) = tuple(map(eltype, p.xss)...) length(p::Product) = prod(map(length, p.xss)) -product(xss...) = Product(xss...) +function product(xss...; order=AntiLexicographicOrder) + if order==AntiLexicographicOrder + Product{order}(xss...) + elseif order==LexicographicOrder + Product{order}(reverse(xss)...) + else + error("Order '$(order)' unsupported") + Product{order}(xss...) + end +end function start(it::Product) n = length(it.xss) @@ -288,10 +303,16 @@ function start(it::Product) return js, vs end -function next(it::Product, state) +function next{T}(it::Product{T}, state) js = copy(state[1]) vs = copy(state[2]) - ans = tuple(vs...) + ans = if T==AntiLexicographicOrder + tuple(vs...) + elseif T==LexicographicOrder + tuple(reverse(vs)...) + else + error("Ordering '$(T)' not supported") + end n = length(it.xss) for i in 1:n diff --git a/test/runtests.jl b/test/runtests.jl index f88ba73..36613a4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -94,6 +94,8 @@ x1 = 1:2:10 x2 = 1:5 @test collect(product(x1, x2)) == vec([(y1, y2) for y1 in x1, y2 in x2]) +@test collect(product(x1, x2, order=LexicographicOrder)) == vec([(y1, y2) for y2 in x2, y1 in x1]) + # distinct # --------