2
$\begingroup$

I really can't find a way how to multiply (repeat) strings in Mathematica. How to write this shorter?

{{"0", "0", "0", "0", "3", "3", "3", "3", "6", "6", "6", "6"}, 
 {"01", "1", "10", "102", "01", "1", "10", "102", "01", "1", "10", "102"}}

Is it possible to code something like this ?

{{4* "0", 4* "3",4* "6"},{3*{"01","1", "10", "102"}}

Edited

Just to let you know, I've used {Flatten[{Table["0", {4}], Table["3", {4}], Table["6", {4}]}, 2], Flatten[{Table[{"01", "1", "10", "102"}, {3}]}, 2]} to get what I want. I will try other stuff right now.

$\endgroup$
5
  • $\begingroup$ How do you multiply strings at all? Any examples in other languages? $\endgroup$
    – LLlAMnYP
    Nov 12, 2015 at 23:18
  • 2
    $\begingroup$ @LLlAMnYP In Java repeated = new String(new char[n]).replace("\0", s) where n is the number of times you want to repeat the string and s is the string to repeat. $\endgroup$
    – Mary
    Nov 12, 2015 at 23:25
  • $\begingroup$ The best I can think is to use a combination of Table and Join but you'd need to have a large number of elements repeated before this becomes more efficient. $\endgroup$
    – IPoiler
    Nov 12, 2015 at 23:38
  • $\begingroup$ I see. But do you actually want a list of strings here, or do you want to concatenate n copies of the same string? $\endgroup$
    – LLlAMnYP
    Nov 12, 2015 at 23:47
  • $\begingroup$ @LLlAMnYP if I understand your question correctly, I want a list of string. This kind of structure { {...},{...} } $\endgroup$
    – Mary
    Nov 12, 2015 at 23:52

5 Answers 5

5
$\begingroup$

Following structure could be applied to achieve the desired outcome. However, this may not be the best way to carry out the OPs request:

Please see example below:

Input:

{Flatten[{Table["x", {3}], Table["y", {4}]}, 2]}

Output:

{{"x", "x", "x", "y", "y", "y", "y"}}

Furthermore, the code can be repeated to reproduce the desired outcome.

Reference:

Table
Flatten

$\endgroup$
4
  • $\begingroup$ yes, it can work! but still long. Is that the shortest way? $\endgroup$
    – Mary
    Nov 12, 2015 at 23:46
  • $\begingroup$ Flatten should only affect level 1 though, because otherwise it can't be used to repeat lists. $\endgroup$
    – C. E.
    Nov 12, 2015 at 23:54
  • $\begingroup$ I think use of Table as the underlying building block is the way forward. However, it's based purely on my current knowledge of Mathematica. There is surely a better way, however the implementation of such would require use of advanced features. I could describe the implementation if anyone more knowledgeable would like to implement it. $\endgroup$ Nov 12, 2015 at 23:57
  • $\begingroup$ @Pickett I agree, I used Flatten in order to achieve the format of the sub-list, essentially this process would need to be repeated to create next sub-list, depending on its configuration (if that makes sense). $\endgroup$ Nov 13, 2015 at 0:06
6
$\begingroup$

I recommend this solution:

data = {"0", "3", "4", "6", {"01", "1", "10", "102"}};
nrOfCopies = {1, 2, 3, 4, 2};
Flatten[MapThread[ConstantArray, {data, nrOfCopies}], 1]

(* Out: {"0", "3", "3", "4", "4", "4", "6", "6", "6", "6", {"01", "1", "10", 
  "102"}, {"01", "1", "10", "102"}} *)

It is possible to get the exact syntax that you ask for, by adding a new definition for the * operator, I just don't like it. If you want this type of syntax but are open to another symbol other than *, then that symbol is of course s = ConstantArray, with Flatten (or Join) appended afterwards.

s = ConstantArray;
Flatten[{s[2, 2], s[3, 3]}, 1]
(* Out: {2, 2, 3, 3, 3} *)
$\endgroup$
6
$\begingroup$

Note that of course none of this requires the elements of the Lists to be Strings.

repeatList[lst_List, nTimes_Integer] := Join @@ ConstantArray[lst, nTimes]
repeatElements[lst_List, {n_Integer}] := Join @@ Map[ConstantArray[#, n] &, lst]
repeatElements[lst_List, ns : {__Integer}] /; Length@lst == Length@ns := Join @@ MapThread[ConstantArray[#1, #2] &, {lst, ns}]

Then

repeatList[{"01", "1", "10", "102"}, 3]
(* {"01", "1", "10", "102", "01", "1", "10", "102", "01", "1", "10", "102"} *)
repeatElements[{"0", "3", "6"}, {4}]
(* {"0", "0", "0", "0", "3", "3", "3", "3", "6", "6", "6", "6"} *)
repeatElements[{"0", "3", "6"}, {4, 3, 2}]
(* {"0", "0", "0", "0", "3", "3", "3", "6", "6"} *)

Then, if you want short, why not take advantage of a symbol with no built-in meaning?

a_Integer⊗b_List := repeatList[b, a]
(a:{__Integer})⊗b_List := repeatElements[b, a]

The symbol is CircleTimes and can be entered quickly in Mathematica as Esc+c+*+Esc. Alternatively, define the functions using the "FullForm" as

CircleTimes[a_Integer, b_List] := repeatList[b, a]
CircleTimes[a:{__Integer}, b_List] := repeatElements[b, a]

Then,

{3}⊗{"01", "1", "10", "102"}
(* {"01", "01", "01", "1", "1", "1", "10", "10", "10", "102", "102", "102"} *)
3⊗{"01", "1", "10", "102"}
(* {"01", "1", "10", "102", "01", "1", "10", "102", "01", "1", "10", "102"} *)
$\endgroup$
1
  • $\begingroup$ I was thinking to define a new function but didn't know how to do that.Thank you a lot! $\endgroup$
    – Mary
    Nov 13, 2015 at 0:15
6
$\begingroup$

This is more for fun, than anything else, but here's a recursive solution as short as possible:

sj[n_, s_] := Sequence[s, sj[n - 1, s]]; sj[1, s_] := s;
{4~sj~"0", 4~sj~"3", 4~sj~"6"}
{"0", "0", "0", "0", "3", "3", "3", "3", "6", "6", "6", "6"}

For the second use case:

SetAttributes[sj, SequenceHold]
sj[n_, {s__}] := {sj[n, Sequence@s]}

4~sj~{"1", "2", "3"}
{"1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3"}

@march was faster on the uptake with Infix notation, but I'd like to point out, that if we're in pursuit of brevity, we can do this with CircleTimes:

n_⊗s_ := s~Sequence~(n-1⊗s); 1⊗s_ := s;
CircleTimes~SetAttributes~SequenceHold;
n_⊗{s__} := {n⊗Sequence@s};

"This" meaning to make definitions with infix notation. I've even set the attributes with infix too :-)

4⊗{"1","2","3"}

will now work as well.

$\endgroup$
12
  • $\begingroup$ +1 for both golfing and Infix notation. And also a clever solution. $\endgroup$
    – march
    Nov 13, 2015 at 0:11
  • $\begingroup$ @march Infix is natural as this is sorta' multiplication. I really like the stuff one can do with functions if one uses Attributes/recursion/other unconventional stuff instead of complex definitions. $\endgroup$
    – LLlAMnYP
    Nov 13, 2015 at 0:14
  • $\begingroup$ Yeah agreed. That's why I chose to use one of the built-ins with no meaning so that the solutions could be written with an Infix operator. $\endgroup$
    – march
    Nov 13, 2015 at 0:15
  • $\begingroup$ @LLlAMnYP Could you please explain why Infix useful here and what it means here? $\endgroup$
    – Mary
    Nov 13, 2015 at 0:18
  • 1
    $\begingroup$ @Maria The normal notation is f[a, b]. For example Times[a, b]. But for certain functions, we are more accustomed to Infix notation: nobody usually writes Times[a,b] or Plus[a,b], everyone write a*b and a+b. * and + are operators. They're called Infix as they stand between the arguments. $\endgroup$
    – LLlAMnYP
    Nov 13, 2015 at 0:20
1
$\begingroup$

It is unclear what the question poser seeks in writing "...this shorter." Nevertheless

ToExpression /@ (x = {{"0", "0", "0", "0", "3", "3", "3", "3", "6", "6", 
   "6", "6"}, {"01", "1", "10", "102", "01", "1", "10", "102", "01", 
   "1", "10", "102"}})

will convert each string into an expression, which you can multiply as you see fit.

4 x[[1]]

3 x[[2]]

or

Inner[{4,3},x]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.