6
$\begingroup$

I have two lists of lists, La and Lb that I want to concatenate so that every element of a list n in La is concatenated with the corresponding element of list n in Lb. For example:

La = {{P, O, O, O}, {C, O, O, C, N}};

Lb = {{1, 2, 3, 4}, {9, 8, 7, 6, 5}};

with the desired result:

Lc = {{P1, O2, O3, O4}, {C9, O8, O7, C6, N5}};

I assume there is an easy way to do this, but I'm new to Mathematica.

$\endgroup$
  • 1
    $\begingroup$ Apply[StringJoin, Transpose /@ Transpose[{La, Lb}], {2}]... $\endgroup$ – ciao Jul 14 '15 at 23:16
  • $\begingroup$ It is not clear if your input lists La and Lb contains already strings or symbols and numbers. Please edit your post to format properly the code part of your question. $\endgroup$ – SquareOne Jul 15 '15 at 15:57
9
$\begingroup$

Here's an approach for any two multi-dimensional lists of strings which have arbitrary, but matching structures:

stringJoin[x__String] := StringJoin[x]
SetAttributes[stringJoin, Listable]
stringJoin[La, Lb]

EDIT
Short explanation of listability:

Listable functions are effectively applied separately to each element in a list, or to corresponding elements in each list if there is more than one list.

In order to prevent premature evaluation of stringJoin[a,b] where a and b are lists, e.g. a = {a1,a2,a3}; b = {b1,b2,b3} leading to "a1a2a3b1b2b3" I have stringJoin accept only String arguments. Then it keeps drilling down to the lowest level until it finally does find a string.

Here's another example. Setting a function f to be listable is almost like replacing every occurrence of f[...] with Thread[f[...]].

list = {a, b, {c, d}, {e, f, g, h}, {i, j, k}}
f[list, list]
(* f[{a, b, {c, d}, {e, f, g, h}, {i, j, k}},
      {a, b, {c, d}, {e, f, g, h}, {i, j, k}}] *)

Now:

Thread[f[list, list]]

{f[a, a], f[b, b],
f[{c, d}, {c, d}], f[{e, f, g, h}, {e, f, g, h}], f[{i, j, k}, {i, j, k}]}

ReplaceRepeated can allow emulation of listability:

f[list, list] //. f[x_, y_] :> Thread[f[x, y]]
(* {f[a, a], f[b, b], {f[c, c], f[d, d]}, {f[e, e], f[f, f], f[g, g], f[h, h]}, {f[i, i], f[j, j], f[k, k]}} *)

Or we can simply do SetAttributes[f, Listable]; f[list, list].

$\endgroup$
  • $\begingroup$ Clever. +1 for out-of-the-box thinking. $\endgroup$ – ciao Jul 15 '15 at 0:39
  • $\begingroup$ @ciao It's because every time I see a task like this and read the answers I'm already expecting a follow-up comment "but with La={{a,b,c,{d,e,f}},{g,h,i}} it doesn't work." Also the arrays in OP are ragged. $\endgroup$ – LLlAMnYP Jul 15 '15 at 0:46
  • 1
    $\begingroup$ Well. I understand your concerns. But within its validity scope your answer is as elegant as they can go $\endgroup$ – Dr. belisarius Jul 15 '15 at 1:45
  • 1
    $\begingroup$ @belisarius - agreed re: elegance, and LLlAMnYP: I hear you, few things irk me more than a question that gets answered with neat solutions only to have OP edit with "well, no, what I meant was... and it needs this and that too..." instead of providing that from the start. (n.b., I am not saying this question is one of those, just commenting on a shared frustration!) $\endgroup$ – ciao Jul 15 '15 at 5:57
  • 1
    $\begingroup$ @ciao It's not even the fear of a follow-up question, it's just that I feel that a general solution has more lasting value to those, who might show up several months later and read it, then a solution that works in a very specific case. Maybe not OP, but another user will ask "what if I have more complex lists", but he won't have to make a new question - my answer will work for him too. Also I get more satisfaction out of solving a generalized problem, unless of course performance starts to suffer significantly. $\endgroup$ – LLlAMnYP Jul 15 '15 at 13:54
5
$\begingroup$
sLa = Map[ToString, La, {2}];
sLb = Map[ToString, Lb, {2}];
MapThread[StringJoin, #] & /@ Transpose[{sLa, sLb}]

also

Thread[j @@ #] & /@ Transpose[{sLa, sLb}] /. j -> StringJoin
$\endgroup$
0
$\begingroup$

Since Plus already does the element-wise addition, you can do:

La + Lb /. Plus -> (List /* Map[ToString] /* StringJoin)

This assumes the elements won't be destroyed by the plus, but as described by LLlAMnYP you can just Listableize the function:

Function[{a, b}, StringJoin[ToString /@ {a, b}], Listable][La, Lb]

or ToString before the operation:

Plus @@ Map[ToString, {La, Lb}, {-1}];
% /. Plus -> StringJoin
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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