3
$\begingroup$

Suppose I have

 listA = {M, F}

and

ListB = {a,b,c}

I want to make a new

listC = {{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}} 

Where I tell Mathematica how many copies of a particular element to make in listC.

Outer[] seems like a good start but it returns the combined elements as a two item list. For example I get {M, a} instead of M a.

$\endgroup$
7
  • 2
    $\begingroup$ Do you mean M * a or a new symbol called Ma ? $\endgroup$ Commented Mar 30, 2013 at 20:03
  • $\begingroup$ "Where I tell Mathematica how many copies of a particular element to make in listC" in what format do you want to supply this information? $\endgroup$
    – acl
    Commented Mar 30, 2013 at 20:10
  • $\begingroup$ Outer seems like the answer, it combines, and wraps a combination of elements with a specified function, if the function is Times, you can get get a M, if it's List, you get {M, a} instead. $\endgroup$
    – BoLe
    Commented Mar 30, 2013 at 20:28
  • $\begingroup$ I edited your question trying to make it easier to read. Next time please try to do it yourself. $\endgroup$ Commented Mar 30, 2013 at 20:40
  • $\begingroup$ @belisarius Thanks for the editing. I am new to the site so I am still trying sort out how things work. I will do that next time. $\endgroup$
    – spaceKnot
    Commented Mar 30, 2013 at 20:59

4 Answers 4

2
$\begingroup$

I just noticed your comment under the question that you actually do want new symbols. I shall give an example of that and also multiplication.

It is more efficient to perform the operation (multiplication, etc.) and then make the copies, rather than making copies and performing the operation anew on each.

f[A_, B_, R_, f_: Times] := Inner[ConstantArray, Outer[f, A, B], R, Join]

f[{M, F}, {a, b, c}, {1, 3, 2}
{{a M, b M, b M, b M, c M, c M}, {a F, b F, b F, b F, c F, c F}}

Symbols:

makeSym = Symbol @ ToString @ Row @ {##} &;

f[{M, F}, {a, b, c}, {1, 3, 2}, makeSym]
{{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}}

With argument checking for practical use:

f[A_List, B_List, R : {__Integer}, f_: Times] /;
 Min[R] >= 0 && Length@B == Length@R :=
  Inner[ConstantArray, Outer[f, A, B], R, Join]
$\endgroup$
5
  • $\begingroup$ Thank you! Very simple to follow the code. However I am not sure I get how makeSym fits in the picture. Is it replacing f_:Times which is the 4th argument when f[A_, B_, R_, f_: Times] gets defined. If that is true, then makeSym is being passed into Outer as the first argument which makes the return value a string? $\endgroup$
    – spaceKnot
    Commented Apr 2, 2013 at 17:43
  • $\begingroup$ @spaceKnot You're welcome. I see that there is an error in my code which I will now correct. (I forgot to update the right-hand-side when I updated the left.) The Pattern: f_: Times defines an Optional parameter with a default values of Times. If no fourth argument is given Times is used where f appears; if an argument is given it instead is used. Sorry for the mistake, and if anything isn't clear please ask again. $\endgroup$
    – Mr.Wizard
    Commented Apr 2, 2013 at 23:11
  • $\begingroup$ Thank you again! That clarified my question :) $\endgroup$
    – spaceKnot
    Commented Apr 4, 2013 at 7:03
  • $\begingroup$ @spaceKnot Are you aware that you can Accept one answer that you find fully satisfactory (and you can change the Accept at a later time)? You are not required to do so but it is appreciated. $\endgroup$
    – Mr.Wizard
    Commented Apr 4, 2013 at 23:52
  • $\begingroup$ @Mr.Wiazrd Sorry, still learning the rules. $\endgroup$
    – spaceKnot
    Commented Apr 5, 2013 at 0:17
3
$\begingroup$

Assuming Ma is the product M * a, you could state the number of copies:

copies = {1, 3, 2};

Then make these copies:

listD = Flatten[Inner[Table[#1, {#2}] &, listB, copies, List]]

{a, b, b, b, c, c}

And finally combine them with the first list:

Outer[Times, listA, listD]

{{a M, b M, b M, b M, c M, c M}, {a F, b F, b F, b F, c F, c F}}

Update

If you really want a new symbol Ma, you could perhaps do this with strings.

listA = {"M", "F"};
listB = {"a", "b", "c"};
copies = {1, 3, 2};
listD = Flatten[Inner[Table[#1, {#2}] &, listB, copies, List]];
Outer[ToExpression[#1 <> #2] &, listA, listD]

{{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}}

$\endgroup$
1
  • $\begingroup$ @spaceKnot Very flexible, this Outer. $\endgroup$
    – BoLe
    Commented Mar 30, 2013 at 21:31
1
$\begingroup$

Another variant of BoLe's answer using Outer:

lA = {"M", "F"};
lB = {"a", "b", "c"};
lC = {1, 3, 2};

Outer[ToExpression[#1 <> #2] &, lA, Flatten[ConstantArray @@@ Transpose@{lB, lC}]] 
(*using AbsoluteTiming*)

{0.0001178, {{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}}}

Outer[ToExpression[#1 <> #2] &, lA, Flatten[Inner[Table[#1, {#2}] &, lB, lC, List]]]
(*using AbsoluteTiming*)

{0.0002433, {{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}}}
$\endgroup$
1
$\begingroup$
mf = {M, F};
abc = {a, b, c};

Map[
  Symbol @* StringJoin,
  Map[
   ToString,
   Thread[{#, abc}] & /@ mf,
   {3}],
  {2}][[All, {1, 2, 2, 2, 3, 3}]]

{{Ma, Mb, Mb, Mb, Mc, Mc}, {Fa, Fb, Fb, Fb, Fc, Fc}}

$\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.