3
$\begingroup$

I have two lists:

list1 = {"a", "b"};
list2 = {{{1, 2}, {3, 4}}, {{1, 2}}};

My goal is to create a new list which would be:

{"a u 1:2","a u 2:3","b u 1:2"}

In other words first element in list1 would be distributed before each subelement of first element in list2 etc.

There are some answers using MapThread e.g. here. But that is not satisfactory, actually, it does not work, just try e.g.

subl = {{{1, 2}, {3, 4}}, {{5, 6}}};
list = {11, 12};
MapThread[Append, {subl, list}]

As it returns: {{{1, 2}, {3, 4}, 11}, {{5, 6}, 12}}

while the result I am seeking should look like:

{{{1,2,11},{3,4,11}},{{5,6,12}}}

And level specification returns errors:

MapThread::mptd: Object {{{1,2},{3,4}},{{5,6}}} at position {2, 1} in MapThread[Append,{{{{1,2},{3,4}},{{5,6}}},{11,12}},2] has only 1 of required 2 dimensions.

or

MapThread::intnm: Non-negative machine-sized integer expected at position 3 in MapThread[Append,{{{{1,2},{3,4}},{{5,6}}},{11,12}},{2}].

Thus I do not think this is a duplicate, or I have not found an answer that would work in this case.

I have:

Map[Function[u, 
  StringRiffle[ToString /@ u, {"u ", ":", ""}]], list2, {2}]

Producing

{{"u 1:2", "u 3:4"}, {"u 1:2"}}

so I had thought simply:

MapThread[
 StringJoin[#2, #1] &, {Map[
   Function[u, StringRiffle[ToString /@ u, {"u ", ":", ""}]], 
   list2, {2}], list1},{2}]

but that gives error and

MapThread[
 StringJoin[#2, #1] &, {Map[
   Function[u, StringRiffle[ToString /@ u, {"u ", ":", ""}]], 
   list2, {2}], list1}]

on the first level gives:

{"a u 1:2u 3:4", "b u 1:2"}

I tried to repartition the lists so that they are similar in size but that did not work. The solution that works is:

listC = Map[Function[u, StringRiffle[ToString /@ u, {"u ", ":", ""}]],
   list2, {2}]
MapThread[Function[{u, v}, StringJoin[u, #] & /@ v], {list1, listC}]

But I do no like it due to the /@v part. I would really like to find a general solution to this problem: redistribute (prepend, apend, join strings) elements in one list across arbitrary dimension of another list (which my solution does not permit, I made use that the in this particular case where i need to apply one level deeper).

$\endgroup$
  • 1
    $\begingroup$ Should it be "a u 3:4" instead of "a u 2:3"? $\endgroup$ – Edmund Nov 11 '17 at 23:27
3
$\begingroup$

The first Map attempt listed in the question gets us close -- a tweak involving MapIndexed can get us all the way:

MapIndexed[StringRiffle[{list1[[#2[[1]]]], #}, " u ", ":"] &, list2, {2}] // Flatten

(* {"a u 1:2", "a u 3:4", "b u 1:2"} *)

Another way is to reshape input lists first and then map StringRiffle across the result:

StringRiffle[#, " u ", ":"] & /@ Inner[Thread@*List, list1, list2, Join]

(* {"a u 1:2", "a u 3:4", "b u 1:2"} *)

The MapIndexed approach is the more general of the two as it allows elements to matched up across the two lists by simple indexing. In contrast, the second approach might look shorter, but it produces more intermediate lists and the exact restructuring operations must be designed for each unique situation.

ReplacePart can be used in a manner that parallels the MapIndexed approach:

ReplacePart[list2, {i_, j_} :> StringRiffle[{list1[[i]], list2[[i, j]]}, " u ", ":"]] // Flatten

Sometimes this is easier to read than the MapIndexed variant.

$\endgroup$
3
$\begingroup$

For the second part of your question, ArrayFlatten and Thread may be combined:

ArrayFlatten[{#}] & /@ Thread[{list1, list2}]

{{{a, 1, 2}, {a, 3, 4}}, {{b, 1, 2}}}

But perhaps more useful is simply the following:

ArrayFlatten@Thread[{list1, list2}] 

{{a, 1, 2}, {a, 3, 4}, {b, 1, 2}}

And, after WReach's answer:

StringRiffle[{#1, " u ", #2, ":", #3}, ""] & @@@ArrayFlatten@Thread[{list1, list2}]

{"a u 1:2", "a u 3:4", "b u 1:2"}

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