# How to join held Lists?

Let's say I have

 a = Hold@{2+2}
b = Hold@{4+4}


How can I get

Hold@{2+2,4+4}


ie join the two held lists ?

More generally I'm looking for a way to be able to do operations on such held lists, like being able to have Dimensions or Length, being able to Prepend or Append (answering this question would allow this) or change some parts of such lists easily.

-
One way would be Thread[Join[a, b]] /. {Hold[x___]} :> Hold[{x}]. –  Leonid Shifrin Sep 11 '13 at 15:30
@Leonid As with everyone else you seem to have forgotten the case where the lists in a and b are not the same length. Or perhaps that's why you didn't post this as an answer. –  Mr.Wizard Sep 11 '13 at 18:04
@Mr.Wizard Not "like anyone else" - I proudly claim to be the first person here to make this mistake :). –  Leonid Shifrin Sep 12 '13 at 14:08

I think there is a case to be made for not using List at all. It seems to me that it is a needless complication. Why not instead use Hold in place of List?

a = Hold[2 + 2];
b = Hold[4 + 4];

c = Join[a, b]

Append[c, Unevaluated[6 + 6]]

Hold[2 + 2, 4 + 4]

Hold[2 + 2, 4 + 4, 6 + 6]


Also:

x = Hold @@ {a, b}

Length[x]

Dimensions[x]

Hold[Hold[2 + 2], Hold[4 + 4]]

2

{2, 1}


Isn't that much cleaner? Where does it fail you?

-
This is cleaner indeed and was aware of this way. I happened to need for manipulating expressions before expanding them in this context mathematica.stackexchange.com/a/24596/66, and the idea seemed interesting to me. But I guess I'll have to adapt my code. Thanks anyway –  faysou Sep 11 '13 at 23:24
@Faysal I glanced at the answer you referenced and I'll admit I don't understand it yet. Could you summarize your need for Hold[{...}] and why that seems more natural than Hold without List? –  Mr.Wizard Sep 12 '13 at 0:37

One easy way, which does not work for lists of different length, is

a = Hold[{2 + 2}];
b = Hold[{4 + 4}];
Thread[{a, b} /. Hold[{a___}] :> Hold[a], Hold]


What happens here is the following: first, you can use

{a, b} /. Hold[{a___}] :> Hold[a]


to get rid of the inner list braces without evaluating your expressions. Since we use {a,b} we will already get the final joined list. The only problem is that the Hold's are inside. For this, we use Thread to turn it inside out.

As pointed out by Mr.Wizard, the approach fails when the list are of different length. For such a case you could use

a = Hold[{1 + 1, 2 + 2}];
b = Hold[{4 + 4}];
Flatten[{a, b} /. List :> Hold, 2, Hold] /. Hold[expr__] :> Hold[{expr}]

-
This fails if the lists are not the same length, e.g. a = Hold[{1 + 1, 2 + 2}]; b = Hold[{4 + 4}]; –  Mr.Wizard Sep 11 '13 at 17:05
@Mr.Wizard You really have to try everything, right? ;-) –  halirutan Sep 11 '13 at 17:36

If the lists are of length 1 as in the example, you can use this:

Thread[{a, b}, Hold][[{1}, All, 1]]


For longer lists there is this:

Thread[Join @@ Thread /@ {a, b}, Hold]

-
This fails if the lists are not length one, e.g. a = Hold@{1 + 1, 2 + 2} –  Mr.Wizard Sep 11 '13 at 17:04
@Mr.Wizard, good point. –  Simon Woods Sep 11 '13 at 17:43
Finally an answer I can vote for. :D –  Mr.Wizard Sep 11 '13 at 18:04
@Mr.Wizard, thank you. I shall now delete the notebook of shame and pretend like this was the most obvious thing that sprang to mind. –  Simon Woods Sep 11 '13 at 18:12
Hahaha :-) I tried several that failed before realizing I could use Sequence since the example is Hold and not HoldComplete. Yours however would work even if it were, with minor change. For HoldComplete I had this bit of nasty I decided not to post: Join[a, b] /. H_[h_[x___], h_[y___]] :> H[h[x, y]] –  Mr.Wizard Sep 11 '13 at 18:14

Answering the question at face value, you might use:

a = Hold@{1 + 1, 2 + 2};

b = Hold@{4 + 4};

Sequence @@@ Join[a, b] /. h_@x__ :> h@{x}

Hold[{1 + 1, 2 + 2, 4 + 4}]

-

Edit2:Coping with my habit of missing subtleties I have tried again to correct it further.

Block[{a = Hold@{2 + 2}, b = Hold@{4 + 4},
l}, {l = HoldForm[Hold[{ {s}, {d}}]] /. {s -> a /. Hold -> Defer,
d -> b /. Hold -> Defer}; Length[l]}
Table[l[[i]] /. List -> Sequence, {i, 1, Length[l]}] /.
HoldPattern[Hold[x___]] :> Hold[{x}]


{Hold[{Sequence[2+2],Sequence[4+4]}]}

To check with @Mr.Wizard's test case of unequal lists, I am getting following output.

Block[{a = Hold@{2 + 2, 1 + 1}, b = Hold@{4 + 4},
l}, {l = HoldForm[Hold[{{s}, {d}}]] /. {s -> a /. Hold -> Defer,
d -> b /. Hold -> Defer}; Length[l]} Table[
l[[i]] /. List -> Sequence, {i, 1, Length[l]}] /.
HoldPattern[Hold[x___]] :> Hold[{x}]]


{Hold[{Sequence[2 + 2, 1 + 1], Sequence[4 + 4]}]} ReleaseHold gives {4,2,8}.

-
The problem is that your expression only looks as your approach works. Use FullForm to see everything. (Beside, that thing Kuba mentioned) –  halirutan Sep 11 '13 at 15:43
yes yes..m looking into it now.Thanks for pointing out. –  Rorschach Sep 11 '13 at 15:45

A way that is quite manual but could be an inspiration for other related operations.

ReleaseAllHold[expr_,firstLevel_:0,lastLevel_:Infinity] :=
Replace[expr,
(Hold|HoldForm|HoldPattern|HoldComplete)[e___] :> e,
{firstLevel, lastLevel},
];

JoinHeldLists[heldLists__Hold]:=
Module[{a,b,c,d},
a={heldLists};
b=Map[Hold,a,{1,-2}];
c=ReleaseAllHold[b,0,-4];
d=Join@@c;
With[{dd=d},
ReleaseAllHold[Hold@dd,1]
]
];

JoinHeldLists[Hold@{2+2},Hold@{4+4}]

-