Skip to content

Commit 2bfbb61

Browse files
committed
Support using colon to omit a dimension in reshape
Closes JuliaLang#16790.
1 parent 28a11ff commit 2bfbb61

File tree

3 files changed

+91
-33
lines changed

3 files changed

+91
-33
lines changed

base/docs/helpdb/Base.jl

-33
Original file line numberDiff line numberDiff line change
@@ -446,39 +446,6 @@ See also [`zeros`](@ref), [`similar`](@ref).
446446
"""
447447
ones
448448

449-
"""
450-
reshape(A, dims)
451-
452-
Create an array with the same data as the given array, but with different dimensions.
453-
454-
```jldoctest
455-
julia> A = collect(1:16)
456-
16-element Array{Int64,1}:
457-
1
458-
2
459-
3
460-
4
461-
5
462-
6
463-
7
464-
8
465-
9
466-
10
467-
11
468-
12
469-
13
470-
14
471-
15
472-
16
473-
474-
julia> reshape(A, (2, 8))
475-
2×8 Array{Int64,2}:
476-
1 3 5 7 9 11 13 15
477-
2 4 6 8 10 12 14 16
478-
```
479-
"""
480-
reshape
481-
482449
"""
483450
randsubseq!(S, A, p)
484451

base/reshapedarray.jl

+70
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,80 @@ start(R::ReshapedArrayIterator) = start(R.iter)
3636
end
3737
length(R::ReshapedArrayIterator) = length(R.iter)
3838

39+
"""
40+
reshape(A, dims...)
41+
reshape(A, dims)
42+
43+
Return an array with the same data as the given array, but with different dimensions.
44+
45+
The new dimensions may be specified either as a list of arguments or as a shape
46+
tuple. At most one dimension may be specified with a `:`, in which case its
47+
length is computed such that its product with all the specified dimensions is
48+
equal to the length of the original array A.
49+
50+
```jldoctest
51+
julia> A = collect(1:16)
52+
16-element Array{Int64,1}:
53+
1
54+
2
55+
3
56+
4
57+
5
58+
6
59+
7
60+
8
61+
9
62+
10
63+
11
64+
12
65+
13
66+
14
67+
15
68+
16
69+
70+
julia> reshape(A, (4, 4))
71+
4×4 Array{Int64,2}:
72+
1 5 9 13
73+
2 6 10 14
74+
3 7 11 15
75+
4 8 12 16
76+
77+
julia> reshape(A, 2, :)
78+
2×8 Array{Int64,2}:
79+
1 3 5 7 9 11 13 15
80+
2 4 6 8 10 12 14 16
81+
```
82+
83+
"""
84+
reshape
85+
3986
reshape(parent::AbstractArray, dims::IntOrInd...) = reshape(parent, dims)
4087
reshape(parent::AbstractArray, shp::NeedsShaping) = reshape(parent, to_shape(shp))
4188
reshape(parent::AbstractArray, dims::Dims) = _reshape(parent, dims)
4289

90+
# Allow missing dimensions with Colon():
91+
reshape(parent::AbstractArray, dims::Int...) = _reshape(parent, dims)
92+
reshape(parent::AbstractArray, dims::Union{Int,Colon}...) = reshape(parent, dims)
93+
reshape(parent::AbstractArray, dims::Tuple{Vararg{Int}}) = _reshape(parent, dims)
94+
reshape(parent::AbstractArray, dims::Tuple{Vararg{Union{Int,Colon}}}) = _reshape(parent, _reshape_uncolon(parent, dims))
95+
# Recursively move dimensions to pre and post tuples, splitting on the Colon
96+
@inline _reshape_uncolon(A, dims) = _reshape_uncolon(A, (), nothing, (), dims)
97+
@inline _reshape_uncolon(A, pre, c::Void, post, dims::Tuple{Any, Vararg{Any}}) =
98+
_reshape_uncolon(A, (pre..., dims[1]), c, post, tail(dims))
99+
@inline _reshape_uncolon(A, pre, c::Void, post, dims::Tuple{Colon, Vararg{Any}}) =
100+
_reshape_uncolon(A, pre, dims[1], post, tail(dims))
101+
@inline _reshape_uncolon(A, pre, c::Colon, post, dims::Tuple{Any, Vararg{Any}}) =
102+
_reshape_uncolon(A, pre, c, (post..., dims[1]), tail(dims))
103+
_reshape_uncolon(A, pre, c::Colon, post, dims::Tuple{Colon, Vararg{Any}}) =
104+
throw(DimensionMismatch("new dimensions $((pre..., c, post..., dims...)) may only have at most one omitted dimension specified by Colon()"))
105+
@inline function _reshape_uncolon(A, pre, c::Colon, post, dims::Tuple{})
106+
sz, remainder = divrem(length(A), prod(pre)*prod(post))
107+
remainder == 0 || _throw_reshape_colon_dimmismatch(A, pre, post)
108+
(pre..., sz, post...)
109+
end
110+
_throw_reshape_colon_dimmismatch(A, pre, post) =
111+
throw(DimensionMismatch("array size $(length(A)) must be divisible by the product of the new dimensions $((pre..., :, post...))"))
112+
43113
reshape{T,N}(parent::AbstractArray{T,N}, ndims::Type{Val{N}}) = parent
44114
function reshape{T,AN,N}(parent::AbstractArray{T,AN}, ndims::Type{Val{N}})
45115
reshape(parent, rdims((), indices(parent), Val{N}))

test/arrayops.jl

+21
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ end
135135
@test isa(reshape(s, Val{N}), Base.ReshapedArray{Int,N})
136136
end
137137
end
138+
@testset "reshape with colon" begin
139+
# Reshape with an omitted dimension
140+
let A = linspace(1, 60, 60)
141+
@test size(reshape(A, :)) == (60,)
142+
@test size(reshape(A, :, 1)) == (60, 1)
143+
@test size(reshape(A, (:, 2))) == (30, 2)
144+
@test size(reshape(A, 3, :)) == (3, 20)
145+
@test size(reshape(A, 2, 3, :)) == (2, 3, 10)
146+
@test size(reshape(A, (2, :, 5))) == (2, 6, 5)
147+
@test_throws DimensionMismatch reshape(A, 7, :)
148+
@test_throws DimensionMismatch reshape(A, :, 2, 3, 4)
149+
@test_throws DimensionMismatch reshape(A, (:, :))
150+
151+
B = rand(2,2,2,2)
152+
@test size(reshape(B, :)) == (16,)
153+
@test size(reshape(B, :, 4)) == (4, 4)
154+
@test size(reshape(B, (2, 1, :))) == (2, 1, 8)
155+
@test_throws DimensionMismatch reshape(B, 3, :)
156+
@test_throws DimensionMismatch reshape(B, :, :, 2, 2)
157+
end
158+
end
138159

139160
@test reshape(1:5, (5,)) === 1:5
140161
@test reshape(1:5, 5) === 1:5

0 commit comments

Comments
 (0)