2
  1. Given a character or a string s, generate a result string with n (an integer) repeats of s
  2. Given a list of characters or strings, and a list of the frequencies of their appearance (in correspondence), generate a result string with each string in the list repeated with the desired times as specified in the second list and StringJoin them together. For example, given {"a", "b", "c"} and {1,0,3}, I want to have "accc".

I of course want to have the most efficient way of doing these. Otherwise, my own way is too ugly and slow.

Thank you for your help!

Qiang Li
  • 10,593
  • 21
  • 77
  • 148
  • 3
    Related question: http://stackoverflow.com/questions/6082172/creating-a-variable-length-string-of-whitespaces-in-mathematica/6082260#6082260 – Leonid Shifrin Nov 17 '11 at 20:47
  • Is the second question because of my answer to the combinations question? I almost included the `MapThread` code in that post, but I decided not to. Should I have? – Mr.Wizard Nov 18 '11 at 01:39
  • Mr. Wizard, exactly as you guessed. :) – Qiang Li Nov 18 '11 at 01:45

3 Answers3

12
rep[s_String, n_] := StringJoin[ConstantArray[s, n]]

then

rep["f", 3]
(*fff*)

next

chars = {"a", "b", "c"};
freqs = {1, 0, 3};

StringJoin[MapThread[rep, {chars, freqs}]]

gives "accc"

acl
  • 6,490
  • 1
  • 27
  • 33
  • I was doing `Nest[StringJoin[s,#]&,"",n]`, of course slower than the built-ins! – Qiang Li Nov 17 '11 at 20:48
  • 2
    @Qiang Li Using `Nest` in this context is analogous to using `AppendTo` for list-building, and leads to the similar quadratic complexity of the solution. This is the main reason for the slowness, not the departure from built-ins per se. – Leonid Shifrin Nov 17 '11 at 20:52
  • There's a flaw, it should be `s_String` not `s__String`; `ConstantArray` will get mad if you pass it more than one string at a time. – rcollyer Nov 17 '11 at 21:02
  • @rcollyer thanks, luck on my part to get the answer first! (the __ was indeed a typo, fixed, thanks) – acl Nov 17 '11 at 21:03
  • yeah, I spent my time linking to the relevant docs, if I hadn't, the answer would have been mine! :P And, I would have still thought I had more than 5k rep ... :( – rcollyer Nov 17 '11 at 21:05
5

For 1, Table will do what you need.

s = "samplestring";

  StringJoin[Table[s, {3}]]

  "samplestringsamplestringsamplestring"

But acl's answer using ContantArray is faster, if you care about the last 1/100th second.

Do[StringJoin[Table[s, {30}]];, {10000}] // Timing

{0.05805, Null}

Do[StringJoin[ConstantArray[s, 30]];, {10000}] // Timing

{0.033306, Null}

Do[StringJoin[Table[s, {300}]];, {10000}] // Timing

{0.39411, Null}

Do[StringJoin[ConstantArray[s, 300]];, {10000}] // Timing

{0.163103, Null}

For 2, MapThread will handle cases where the second list is known to be non-negative integers.

StringJoin @ 
 MapThread[Table[#1, {#2}] &, {{"a", "b", "c"} , {1, 0, 3}}]

"accc"

If the second list contains negative integers, these are treated as zeros.

Non-integer elements in the second list are treated as if they are the integer part. I am not sure if this is what you want.

StringJoin @ 
 MapThread[Table[#1, {#2}] &, {{"a", "b", "c"} , {1, 0, 3.7}}]

"accc"
Verbeia
  • 4,400
  • 2
  • 23
  • 44
2

Knowing your application I propose using Inner:

sets = {{0, 0, 0, 4}, {0, 0, 1, 3}, {0, 1, 0, 3}, {0, 1, 1, 2}, {0, 2, 0, 2},
        {0, 2, 1, 1}, {1, 0, 0, 3}, {1, 0, 1, 2}, {1, 1, 0, 2}, {1, 1, 1, 1},
        {1, 2, 0, 1}, {1, 2, 1, 0}, {2, 0, 0, 2}, {2, 0, 1, 1}, {2, 1, 0, 1},
        {2, 1, 1, 0}, {2, 2, 0, 0}};

chars = {"a", "b", "c", "d"};

Inner[ConstantArray[#2, #] &, sets, chars, StringJoin]
{"dddd", "cddd", "bddd", "bcdd", "bbdd", "bbcd", "addd", "acdd",
"abdd", "abcd", "abbd", "abbc", "aadd", "aacd", "aabd", "aabc", "aabb"}
Community
  • 1
  • 1
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125