9

In Python, ['a'] * 10 generates

['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']

and 10 * [1,2] gives

[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]

How can I replicate an approximation of this infix syntax?

Update: I'm trying to use InfixNotation from Needs["Notation`"] but no luck so far.

M.R.
  • 31,425
  • 8
  • 90
  • 281

7 Answers7

14

The Notation package is not necessary to use an infix form of \[Star] as that is handled automatically. Also I recommend PadRight for constructing your expression (reference Generating a matrix using sublists A and B n times).

SetAttributes[Star, HoldFirst]

Star[a_List, n_Integer] := PadRight[a, n*Length@a, a]

{1, 2}⋆5    (*  ⋆ is \[Star]  *)
{1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

\[Star] may be entered with EscstarEsc.


Performance

Let me demonstrate why I recommend PadRight instead of Sequence in ConstantArray:

foo = Range[100];
n = 250000;

ConstantArray[Unevaluated[Sequence @@ foo], n] // ByteCount // RepeatedTiming
PadRight[foo, Length[foo]*n, foo]              // ByteCount // RepeatedTiming
{1.18, 600000080}

{0.0470, 200000144}

So here PadRight is 25 times faster, and because the output is a packed array it uses one third the memory.

One may be tempted to use "Periodic" padding but unfortunately it is slower:

PadRight[foo, Length[foo]*n, "Periodic"] // ByteCount // RepeatedTiming
{0.4805, 200000144}

Still a packed array and faster than Sequence however!

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • One could use "Periodic" for the padding. – Karsten7 Jul 29 '15 at 20:58
  • @Karsten PadRight is much faster than ConstantArray when used well. "Periodic" looks nice but slows down PadRight, but still not so much as to be as slow as ConstantArray. I'll add timings to this post. – Mr.Wizard Jul 29 '15 at 21:11
  • @Karsten Please see the update. If your results do not agree please tell me which version you are using. – Mr.Wizard Jul 29 '15 at 21:19
10
Unevaluated@Sequence[1, 2]~ConstantArray~10

$\ $ {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

Or using Notation

<< Notation`

Notation[ParsedBoxWrapper[
RowBox[{
RowBox[{"[", "const_", "]"}], "\[Star]", 
     "reps_"}]] \[DoubleLongRightArrow] ParsedBoxWrapper[
RowBox[{
RowBox[{"Unevaluated", "@", 
RowBox[{"Sequence", "[", "const_", "]"}]}], "~", "ConstantArray", "~",
      "reps_"}]]]

Now

[1, 2]\[Star]10

$\ $ {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

Which displays as ScreenSnipped


Using InfixNotation

pythonStar[const_List, reps_Integer] := ConstantArray[Unevaluated[Sequence @@ const], reps]

InfixNotation[ParsedBoxWrapper["\[Star]"], pythonStar]

Now

{1, 2}\[Star]10

$\ $ {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

Karsten7
  • 27,448
  • 5
  • 73
  • 134
10

Brief? How about this. Define:

c = ConstantArray;

Now you can get what you want using the infix notation:

"a"~c~7

and

10~c~7 

With lists

{1, 2}~c~7

you'll need to Flatten.

bill s
  • 68,936
  • 4
  • 101
  • 191
3

Define p for python:

a_ ~ p ~ b_List := Table[Splice[b], a]
a_ ~ p ~ b_ := Table[b, a]

10~p~{1, 2}

{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

5~p~"a"

{"a", "a", "a", "a", "a"}

eldo
  • 67,911
  • 5
  • 60
  • 168
3

TagSetDelayed

g /: g[x__] * y_ :=
    ConstantArray[{x}, y] // Flatten

g /: y_ * g[x__] := ConstantArray[{x}, y] // Flatten

g[1, 2] * 5

5 * g[1, 2]

AsukaMinato
  • 9,758
  • 1
  • 14
  • 40
3

There is an infix operator named Star which can be entered as esc star esc and looks exactly like the multiplication sign:

a_\[Star]b_List := Table[Splice[b], a]
a_\[Star]b_ := Table[b, a]

?Star

enter image description here

10 * {1, 2}

{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}

5 * "a"

{"a", "a", "a", "a", "a"}

Again: write the above as: 5 esc star esc "a"

Documentation

Language Guide

Operators without built-in meanings

eldo
  • 67,911
  • 5
  • 60
  • 168
1

Other possibilities

SubstitutionSystem[{1->1,2->2},{1,2},9] // Flatten

SubstitutionSystem[{1->2,2->1},1,19] // Flatten

(* {1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2} {1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2} *)

and

NestList[#&,{1,2},9]//Flatten

(* {1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2} *)

user1066
  • 17,923
  • 3
  • 31
  • 49