1
1
module KWayMerges
2
2
3
- export KWayMerger
3
+ using Base. Order: Ordering, Forward, ord, lt
4
+
5
+ export kway_merge
6
+ public KWayMerger
4
7
5
8
include (" heap.jl" )
6
9
7
10
"""
8
- KWayMerger{T, I, F}(f::F, iterators)
9
- KWayMerger{T, I}(iterators)
10
- KWayMerger(f, iterators)
11
- KWayMerger(iterators)
11
+ KWayMerger{T, I, O, S}
12
+
13
+ Stateful iterator of a k-way merge of multiple iterators of the same type.
14
+ Constructed using [`kway_merge`](@ref).
15
+
16
+ The type parameters are:
17
+ * `T`: Element type of iterators
18
+ * `I`: Iterator type
19
+ * `O`: Ordering, subtype of `Base.Ordering`
20
+ * `S`: Type of state of iterators
21
+ """
22
+ struct KWayMerger{T, I, O <: Base.Ordering , S}
23
+ ordering:: O
24
+ iterators:: Vector{I}
25
+ states:: Vector{S}
26
+ heap:: Vector{@NamedTuple{from_iter::Int, value::T}}
27
+ end
28
+
29
+ """
30
+ kway_merge(
31
+ iterators;
32
+ lt=isless,
33
+ by=identity,
34
+ rev::Bool=false,
35
+ order::Base.Order.Ordering=Base.Order.Forward
36
+ )
37
+ kway_merge(::Type{T}, ::Type{T}, iterators; kwargs...)
38
+ kway_merge(::Type{T}, ::Type{T}, ordering::Ordering, iterators)
12
39
13
40
Create a stateful iterator which does a k-way merge between multiple
14
41
iterators of the same type.
15
42
16
43
This iterator yields `@NamedTuple{from_iter::Int, value::T}` elements, where `value` is the
17
44
next element from one of the iterators, and `from_iter` is the 1-based index of the iterator
18
45
that yielded `value`.
19
- The element `value` are chosenis from among the iterators such that, among all elements which
20
- are the next element of the iterators, the element is chosen which is the smallest
21
- according to the predicate `f::F`, which defaults to `isless`.
22
-
23
- This implies that if all iterators are sorted by `f`, the yielded will be in sorted
24
- order.
46
+ The element `value` is chosen among the iterators such that, among all elements which
47
+ are the next element of the iterators, the element is chosen which is the first
48
+ according to the ordering.
49
+ This implies that if all iterators are sorted by `f`, the yielded will be in sorted order.
25
50
Hence, a `KWayMerger` is typically used to combined multiple sorted arrays
26
51
into one sorted array.
27
52
53
+ The ordering is given by the keywords `by`, `lt`, `rev` and `order` - these are the
54
+ same as for `Base.sort!`.
55
+
56
+
28
57
# Examples
29
58
```jldoctest
30
59
julia> arrs = [[1,6], [2], [5,7], [3,4,8]];
@@ -41,31 +70,17 @@ julia> print(map(Tuple, it))
41
70
```
42
71
43
72
# Extended help
44
- The type parameters are:
45
- * `F`: Type of function used to compare the elements. It defaults
46
- to `typeof(Base.isless)`
47
- * `T`: Element type of iterators
48
- * `I`: Iterator type
49
- * `S`: Type of state of iterators
50
-
51
73
All iterators must be of the same type. For the constructors which don't pass
52
74
in `T` and `I` explicitly, `Base.eltype` is used
53
75
to determine them; since its default implementation
54
76
returns `Any`, explicitly passing them may be needed for good performance for some
55
77
iterators.
56
78
57
79
`S` is derived automatically, but this must be a fixed type;
58
- iterators that use states of multiple different types may
59
- not be supported by `KWayMerger` .
80
+ iterators that use states of multiple different types during iteration may
81
+ not be supported.
60
82
"""
61
- struct KWayMerger{T, I, F, S}
62
- f:: F
63
- iterators:: Vector{I}
64
- states:: Vector{S}
65
- heap:: Vector{@NamedTuple{from_iter::Int, value::T}}
66
- end
67
-
68
- function KWayMerger {T, I, F} (f:: F , iterators) where {T, I, F}
83
+ function kway_merge (:: Type{T} , :: Type{I} , ordering:: O , iterators) where {T, I, O}
69
84
iters = vec (collect (iterators))
70
85
states = nothing
71
86
things = @NamedTuple {from_iter:: Int , value:: T }[]
@@ -79,25 +94,32 @@ function KWayMerger{T, I, F}(f::F, iterators) where {T, I, F}
79
94
push! (things, (; from_iter = i, value))
80
95
states[i] = state
81
96
end
82
- heapify! (f , things)
97
+ heapify! (ordering , things)
83
98
states = if isnothing (states)
84
99
Vector {Union{}} (undef, length (iters))
85
100
else
86
101
states
87
102
end
88
- return KWayMerger {T, I, F , eltype(states)} (f , iters, states, things)
103
+ return KWayMerger {T, I, O , eltype(states)} (ordering , iters, states, things)
89
104
end
90
105
91
- function KWayMerger {T, I} (iterators) where {T, I}
92
- return KWayMerger {T, I, typeof(isless)} (isless, iterators)
106
+ function kway_merge (
107
+ :: Type{T} ,
108
+ :: Type{I} ,
109
+ iterators;
110
+ lt = isless,
111
+ by = identity,
112
+ rev:: Bool = false ,
113
+ order:: Base.Ordering = Forward,
114
+ ) where {T, I}
115
+ ordering = ord (lt, by, rev, order)
116
+ return kway_merge (T, I, ordering, iterators)
93
117
end
94
118
95
- KWayMerger (iterators) = KWayMerger (isless, iterators)
96
-
97
- function KWayMerger (f:: F , iterators) where {F}
119
+ function kway_merge (iterators; kwargs... )
98
120
I = eltype (typeof (iterators))
99
121
T = eltype (I)
100
- return KWayMerger { T, I, F} (f, iterators)
122
+ return kway_merge ( T, I, iterators; kwargs ... )
101
123
end
102
124
103
125
# We could technically know this, but KWayMerger is stateful, and
@@ -112,11 +134,15 @@ function Base.iterate(x::KWayMerger, ::Nothing = nothing)
112
134
state = @inbounds x. states[top. from_iter]
113
135
it = iterate (iterator, state)
114
136
if it === nothing
115
- @inbounds heappop! (x. f , x. heap)
137
+ @inbounds heappop! (x. ordering , x. heap)
116
138
else
117
139
(new_item, new_state) = it
118
140
@inbounds x. states[top. from_iter] = new_state
119
- @inbounds heapreplace! (x. f, x. heap, (; from_iter = top. from_iter, value = new_item))
141
+ @inbounds heapreplace! (
142
+ x. ordering,
143
+ x. heap,
144
+ (; from_iter = top. from_iter, value = new_item)
145
+ )
120
146
end
121
147
return (top, nothing )
122
148
end
0 commit comments