Reputation: 2912
This question shows how to repeat individual characters in strings in Python.
>>> s = '123abc'
>>> n = 3
>>> ''.join([c*n for c in s])
'111222333aaabbbccc'
How would you do that in Julia?
EDIT
As a newcomer to Julia I am amazed at what the language has to offer.
For example, I would have thought that the Python code above is about as simple as the code could get in any language. However, as shown by my answer below, the Julia equivalent code join([c^n for c in s])
is arguably simpler, and may be reaching the optimum of simplicity for any language.
On the other hand, @niczky12 has shown that with the addition of the ellipsis operator to the string
function, the speed can be substantially increased over what the somewhat simpler join
function achieves.
In one case Julia shines for simplicity. In the other case, Julia shines for speed.
To a Python programmer the first case should be almost immediately readable when they notice that c^n
is just c*n
in Python. When they see the speed increase using the ...
ellipsis operator, the extra complexity might not deter them from learning Julia. Readers might be starting to think I hope many Python programmers will take Julia seriously. They would not be wrong.
Thanks to @rickhg12hs for suggesting bench-marking. I have learned a lot.
Upvotes: 3
Views: 348
Reputation: 5073
In addition to the answers above, I found that the string
function runs even faster. Here are my benchmarks:
julia> n = 2;
julia> s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
julia> string((c^n for c in s)...) # proof that it works
"AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ"
julia> n = 26000;
julia> @benchmark join(c^n for c in s)
BenchmarkTools.Trial:
memory estimate: 1.44 MiB
allocs estimate: 36
--------------
minimum time: 390.616 μs (0.00% GC)
median time: 425.861 μs (0.00% GC)
mean time: 484.638 μs (6.54% GC)
maximum time: 45.006 ms (98.99% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark string((c^n for c in s)...)
BenchmarkTools.Trial:
memory estimate: 1.29 MiB
allocs estimate: 31
--------------
minimum time: 77.480 μs (0.00% GC)
median time: 101.667 μs (0.00% GC)
mean time: 126.455 μs (0.00% GC)
maximum time: 832.524 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
As you can see it's about 3 times faster than the join
solution proposed by @Julia Learner.
I tested the above on 0.7 but had no deprecation warnings so I'm assuming it works fine on 1.0 too. Even TIO says so.
Upvotes: 2
Reputation: 2912
You can do it with either a Julia comprehension or a generator.
julia> VERSION
v"1.0.0"
julia> s = "123abc"
"123abc"
# n is number of times to repeat each character.
julia> n = 3
3
# Using a Julia comprehension with [...]
julia> join([c^n for c in s])
"111222333aaabbbccc"
# Using a Julia generator without the [...]
julia> join(c^n for c in s)
"111222333aaabbbccc"
For small strings there should be little practical difference in speed.
Edit
TL;DR: In general, the generator is somewhat faster than the comprehension. However, see case 3 for the opposite. The memory estimates were very similar.
@rickhg12hs has suggested it would be nice to have benchmarks.
Using the great BenchmarkTools package, the results are below.
n = the number of times to repeat each character
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" in each case
In each case, the comprehension median time, C, is listed first, vs the generator median time, G, second. The times were rounded as seemed appropriate and the original figures are below the numbered summaries. Smaller, of course, is better.
The memory estimates were not very different.
1. n = 26, C=3.8 vs. G=2.8 μs, G faster
julia> using BenchmarkTools
julia> n = 26;
julia> @benchmark join([c^n for c in s])
BenchmarkTools.Trial:
memory estimate: 3.55 KiB
allocs estimate: 39
--------------
minimum time: 3.688 μs (0.00% GC)
median time: 3.849 μs (0.00% GC)
mean time: 4.956 μs (16.27% GC)
maximum time: 5.211 ms (99.85% GC)
--------------
samples: 10000
evals/sample: 8
julia> @benchmark join(c^n for c in s)
BenchmarkTools.Trial:
memory estimate: 3.19 KiB
allocs estimate: 36
--------------
minimum time: 2.661 μs (0.00% GC)
median time: 2.756 μs (0.00% GC)
mean time: 3.622 μs (19.94% GC)
maximum time: 4.638 ms (99.89% GC)
--------------
samples: 10000
evals/sample: 9
2. n = 260, C=10.7 vs. G=8.1 μs, G faster
julia> n = 260;
julia> @benchmark join([c^n for c in s])
BenchmarkTools.Trial:
memory estimate: 19.23 KiB
allocs estimate: 39
--------------
minimum time: 8.125 μs (0.00% GC)
median time: 10.691 μs (0.00% GC)
mean time: 18.559 μs (35.36% GC)
maximum time: 43.930 ms (99.92% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark join(c^n for c in s)
BenchmarkTools.Trial:
memory estimate: 18.88 KiB
allocs estimate: 36
--------------
minimum time: 7.270 μs (0.00% GC)
median time: 8.126 μs (0.00% GC)
mean time: 10.872 μs (18.04% GC)
maximum time: 10.592 ms (99.87% GC)
--------------
samples: 10000
evals/sample: 4
3. n = 2,600, C=62.3 vs. G=63.7 μs, C faster
julia> n = 2600;
julia> @benchmark join([c^n for c in s])
BenchmarkTools.Trial:
memory estimate: 150.16 KiB
allocs estimate: 39
--------------
minimum time: 51.746 μs (0.00% GC)
median time: 63.293 μs (0.00% GC)
mean time: 77.315 μs (2.79% GC)
maximum time: 3.721 ms (96.85% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark join(c^n for c in s)
BenchmarkTools.Trial:
memory estimate: 149.80 KiB
allocs estimate: 36
--------------
minimum time: 47.897 μs (0.00% GC)
median time: 63.720 μs (0.00% GC)
mean time: 88.716 μs (17.58% GC)
maximum time: 42.457 ms (99.83% GC)
--------------
samples: 10000
evals/sample: 1
4. n = 26,000, C=667 vs. G=516 μs, G faster
julia> n = 26000;
julia> @benchmark join([c^n for c in s])
BenchmarkTools.Trial:
memory estimate: 1.44 MiB
allocs estimate: 39
--------------
minimum time: 457.589 μs (0.00% GC)
median time: 666.710 μs (0.00% GC)
mean time: 729.592 μs (10.91% GC)
maximum time: 42.673 ms (98.76% GC)
--------------
samples: 6659
evals/sample: 1
julia> @benchmark join(c^n for c in s)
BenchmarkTools.Trial:
memory estimate: 1.44 MiB
allocs estimate: 36
--------------
minimum time: 475.977 μs (0.00% GC)
median time: 516.176 μs (0.00% GC)
mean time: 659.001 μs (10.36% GC)
maximum time: 42.268 ms (98.41% GC)
--------------
samples: 7548
evals/sample: 1
Upvotes: 2
Reputation: 11
Code tested in Version 1.0.0 (2018-08-08)
.
When I'am trying to write map(x -> x^3, "123abc")
, I got an error.
julia> map(x -> x^3, "123abc")
ERROR: ArgumentError: map(f, s::AbstractString) requires f to return AbstractChar; try map(f, collect(s)) or a comprehension instead
So, There's another way to do that.
julia> map(x -> x^3, collect("123abc"))
6-element Array{String,1}:
"111"
"222"
"333"
"aaa"
"bbb"
"ccc"
julia> join(map(x -> x^3, collect("123abc")))
"111222333aaabbbccc"
And Maybe repeat
is more convenient.
julia> repeat(collect("123abc"), inner=3)
18-element Array{Char,1}:
'1'
'1'
'1'
'2'
'2'
'2'
'3'
'3'
'3'
'a'
'a'
'a'
'b'
'b'
'b'
'c'
'c'
'c'
julia> join(repeat(collect("123abc"), inner=3))
"111222333aaabbbccc"
Upvotes: 1