Skip to content

Commit

Permalink
add rand(::String) (#22224)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet authored Jun 15, 2017
1 parent 887064e commit 1c40bab
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 9 deletions.
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ Library improvements
* The function `randn` now accepts complex arguments (`Complex{T <: AbstractFloat}`)
([#21973]).

* The function `rand` can now pick up random elements from strings, associatives
and sets ([#22228], [#21960], [#18155], [#22224]).

* Method lists are now printed as a numbered list. In addition, the source code of a
method can be opened in an editor by entering the corresponding number in the REPL
and pressing `^Q` ([#22007]).
Expand Down Expand Up @@ -749,6 +752,7 @@ Command-line option changes
[#17785]: https://github.com/JuliaLang/julia/issues/17785
[#18012]: https://github.com/JuliaLang/julia/issues/18012
[#18050]: https://github.com/JuliaLang/julia/issues/18050
[#18155]: https://github.com/JuliaLang/julia/issues/18155
[#18159]: https://github.com/JuliaLang/julia/issues/18159
[#18218]: https://github.com/JuliaLang/julia/issues/18218
[#18251]: https://github.com/JuliaLang/julia/issues/18251
Expand Down Expand Up @@ -882,6 +886,7 @@ Command-line option changes
[#21759]: https://github.com/JuliaLang/julia/issues/21759
[#21818]: https://github.com/JuliaLang/julia/issues/21818
[#21825]: https://github.com/JuliaLang/julia/issues/21825
[#21960]: https://github.com/JuliaLang/julia/issues/21960
[#21973]: https://github.com/JuliaLang/julia/issues/21973
[#21974]: https://github.com/JuliaLang/julia/issues/21974
[#22007]: https://github.com/JuliaLang/julia/issues/22007
Expand All @@ -890,3 +895,7 @@ Command-line option changes
[#22064]: https://github.com/JuliaLang/julia/issues/22064
[#22187]: https://github.com/JuliaLang/julia/issues/22187
[#22188]: https://github.com/JuliaLang/julia/issues/22188
[#22224]: https://github.com/JuliaLang/julia/issues/22224
[#22228]: https://github.com/JuliaLang/julia/issues/22228
[#22245]: https://github.com/JuliaLang/julia/issues/22245
[#22310]: https://github.com/JuliaLang/julia/issues/22310
32 changes: 30 additions & 2 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,9 @@ globalRNG() = GLOBAL_RNG
Pick a random element or array of random elements from the set of values specified by `S`; `S` can be
* an indexable collection (for example `1:n` or `['x','y','z']`), or
* an `Associative` or `AbstractSet` object, or
* an indexable collection (for example `1:n` or `['x','y','z']`),
* an `Associative` or `AbstractSet` object,
* a string (considered as a collection of characters), or
* a type: the set of values to pick from is then equivalent to `typemin(S):typemax(S)` for
integers (this is not applicable to [`BigInt`](@ref)), and to ``[0, 1)`` for floating
point numbers;
Expand Down Expand Up @@ -709,6 +710,33 @@ end
rand(rng::AbstractRNG, r::AbstractArray{T}, dims::Dims) where {T} = rand!(rng, Array{T}(dims), r)
rand(rng::AbstractRNG, r::AbstractArray, dims::Integer...) = rand(rng, r, convert(Dims, dims))

# rand from a string

isvalid_unsafe(s::String, i) = !Base.is_valid_continuation(unsafe_load(pointer(s), i))
isvalid_unsafe(s::AbstractString, i) = isvalid(s, i)
_endof(s::String) = s.len
_endof(s::AbstractString) = endof(s)

function rand(rng::AbstractRNG, s::AbstractString)::Char
g = RangeGenerator(1:_endof(s))
while true
pos = rand(rng, g)
isvalid_unsafe(s, pos) && return s[pos]
end
end

rand(s::AbstractString) = rand(GLOBAL_RNG, s)

## rand from a string for arrays
# we use collect(str), which is most of the time more efficient than specialized methods
# (except maybe for very small arrays)
rand!(rng::AbstractRNG, A::AbstractArray, str::AbstractString) = rand!(rng, A, collect(str))
rand!(A::AbstractArray, str::AbstractString) = rand!(GLOBAL_RNG, A, str)
rand(rng::AbstractRNG, str::AbstractString, dims::Dims) = rand!(rng, Array{eltype(str)}(dims), str)
rand(rng::AbstractRNG, str::AbstractString, d1::Integer, dims::Integer...) = rand(rng, str, convert(Dims, tuple(d1, dims...)))
rand(str::AbstractString, dims::Dims) = rand(GLOBAL_RNG, str, dims)
rand(str::AbstractString, d1::Integer, dims::Integer...) = rand(GLOBAL_RNG, str, d1, dims...)

## random BitArrays (AbstractRNG)

function rand!(rng::AbstractRNG, B::BitArray)
Expand Down
19 changes: 12 additions & 7 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,9 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
1:100 => Int,
rand(Int, 100) => Int,
Int => Int,
Float64 => Float64]

Float64 => Float64,
"qwèrtï" => Char,
GenericString("qwèrtï") => Char]
b2 = big(2)
u3 = UInt(3)
for f in [rand, randn, randexp]
Expand All @@ -346,10 +347,13 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
a0 = rand(rng..., C) ::T
a1 = rand(rng..., C, 5) ::Vector{T}
a2 = rand(rng..., C, 2, 3) ::Array{T, 2}
a3 = rand(rng..., C, b2, u3) ::Array{T, 2}
a4 = rand!(rng..., Array{T}(5), C) ::Vector{T}
a5 = rand!(rng..., Array{T}(2, 3), C) ::Array{T, 2}
for a in [a0, a1..., a2..., a3..., a4..., a5...]
a3 = rand(rng..., C, (2, 3)) ::Array{T, 2}
a4 = rand(rng..., C, b2, u3) ::Array{T, 2}
a5 = rand!(rng..., Array{T}(5), C) ::Vector{T}
a6 = rand!(rng..., Array{T}(2, 3), C) ::Array{T, 2}
@test size(a1) == (5,)
@test size(a2) == size(a3) == (2, 3)
for a in [a0, a1..., a2..., a3..., a4..., a5..., a6...]
if C isa Type
@test a isa C
else
Expand All @@ -358,7 +362,8 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()])
end
end
for C in [1:0, Dict(), Set(), IntSet(), Int[],
GenericDict(Dict()), GenericSet(Set())]
GenericDict(Dict()), GenericSet(Set()),
"", Base.Test.GenericString("")]
@test_throws ArgumentError rand(rng..., C)
@test_throws ArgumentError rand(rng..., C, 5)
end
Expand Down

0 comments on commit 1c40bab

Please sign in to comment.