8

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.

Kuba
  • 136,707
  • 13
  • 279
  • 740
faysou
  • 10,999
  • 3
  • 50
  • 125

6 Answers6

8

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?

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • This is cleaner indeed and was aware of this way. I happened to need for manipulating expressions before expanding them in this context http://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 00:37
6

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}]
halirutan
  • 112,764
  • 7
  • 263
  • 474
4

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]
Simon Woods
  • 84,945
  • 8
  • 175
  • 324
  • 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
4

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}]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
0

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}.

Pankaj Sejwal
  • 2,063
  • 14
  • 23
0

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}, 
  Heads -> True
 ];

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}]
rcollyer
  • 33,976
  • 7
  • 92
  • 191
faysou
  • 10,999
  • 3
  • 50
  • 125