3
$\begingroup$

I want to convert {Hold[1 + 2], Hold[3 + 4], Hold[5*6]} into Hold[{1 + 2, 3 + 4, 5*6}].

I have tried

{Hold[1 + 2], Hold[3 + 4],  Hold[5*6]} /. {Hold[a_], Hold[b_], Hold[c_]} -> Hold[{a, b, c}]
Hold[{1 + 2, 3 + 4, 5 6}]

Is there a simpler way?

$\endgroup$
5
  • 1
    $\begingroup$ Related (perhaps duplicate): Join held lists, Injecting Sequence into Hold. $\endgroup$ Oct 26, 2013 at 7:07
  • $\begingroup$ It's a shame this question was closed as a duplicate. I would use: Distribute[{Hold[1 + 2], Hold[3 + 4], Hold[5*6]}, Hold]. $\endgroup$
    – Carl Woll
    Jun 7, 2017 at 5:41
  • 1
    $\begingroup$ @CarlWoll what's the benefit of Distribute over Thread there? $\endgroup$
    – b3m2a1
    Jun 8, 2017 at 4:28
  • $\begingroup$ @CarlWoll I must be missing something. Wouldn't your answer be equally valid to (32119)? Why reopen this one rather than answering that one? $\endgroup$
    – Mr.Wizard
    Jun 11, 2017 at 15:01
  • $\begingroup$ @Mr.Wizard I wanted to discuss the step in this question in a bit more detail, that is the {__Hold} -> Hold[_List] transformation. In question 32119, this transformation can be used as one piece of an answer, but there are many answers that don't use this transformation at all. $\endgroup$
    – Carl Woll
    Jun 11, 2017 at 18:06

4 Answers 4

4
$\begingroup$

Join works with every Head so it seems to be the best way here:

Join @@ {Hold[1 + 2], Hold[3 + 4], Hold[5*6]}
Hold[1 + 2, 3 + 4, 5 6]

and if you really need those {} inside:

% /. Hold[x__] :> Hold[{x}]
Hold[{1 + 2, 3 + 4, 5 6}]
$\endgroup$
3
$\begingroup$

One way which works no matter how many elements your list has is to use Flatten

expr = {Hold[1 + 2], Hold[3 + 4], Hold[5*6]};
Flatten[Hold @@ expr, 1, Hold]

(* Hold[1 + 2, 3 + 4, 5 6] *)

You see that the list braces are not created. They could be reconstructed too but the question is whether you really need them. I assume for your purpose it is not really a difference whether you have List[e1,e2,...] or Hold[e1,e2,...] but Hold has the advantage of not evaluating your expression.

If you want the list, you can add another rule

expr /. {a__Hold} :> Flatten[Hold[a], 1, Hold] /. 
 Hold[a__] :> Hold[{a}]

(* Hold[{1 + 2, 3 + 4, 5 6}] *)

Or you define a function which basically does the same but the rules are hidden in the DownValues

f[{a__}] := f[a];
f[a__Hold] := f[Flatten[Hold[a], 1, Hold]];
f[Hold[a__]] := Hold[{a}];

f[expr]

(* Hold[{1 + 2, 3 + 4, 5 6}] *)
$\endgroup$
3
$\begingroup$

A couple direct ways of doing this are to use Thread and Distribute.

Thread[{Hold[1 + 2], Hold[3 + 4],  Hold[5*6]}, Hold]
Distribute[{Hold[1 + 2], Hold[3 + 4],  Hold[5*6]}, Hold]

Hold[{1 + 2, 3 + 4, 5 6}]

Hold[{1 + 2, 3 + 4, 5 6}]

The problem with Distribute is that it distributes, so if the Hold objects have more than one argument, you will get probably unwanted distribution.

Distribute[{Hold[1+2, x], Hold[3+4], Hold[5+6]}, Hold]

Hold[{1 + 2, 3 + 4, 5 + 6}, {x, 3 + 4, 5 + 6}]

On the other hand, the nice thing about Distribute is that you can stick in arbitrary heads:

SetAttributes[f, HoldAll];
Distribute[{Hold[1+2], Hold[3+4], Hold[5*6]}, Hold, List, f, g]

f[g[1 + 2, 3 + 4, 5 6]]

Just like Distribute, Thread may not work as desired when the Hold objects have more than one argument:

Thread[{Hold[1 + 2, x], Hold[3 + 4],  Hold[5*6]}, Hold]

Thread::tdlen: Objects of unequal length in {Hold[1+2,x],Hold[3+4],Hold[5 6]} cannot be combined.

{Hold[1 + 2, x], Hold[3 + 4], Hold[5 6]}

Thread[{Hold[1 + 2, x], Hold[3 + 4, y], Hold[5*6, z]}, Hold]

Hold[{1 + 2, 3 + 4, 5 6}, {x, y, z}]

Finally, Thread has support for a 3rd argument, although I don't think I've ever used it:

Thread[{Hold[1+2, x], Hold[3 + 4], Hold[5*6]}, Hold, 1]

Hold[{1 + 2, Hold[3 + 4], Hold[5 6]}, {x, Hold[3 + 4], Hold[5 6]}]

Summarizing, I find Distribute and Thread useful when working with Hold objects.

$\endgroup$
2
$\begingroup$

Here is an interesting way:

expr = {Hold[1 + 2], Hold[3 + 4], Hold[5*6]};
expr /. {Hold -> Sequence, List -> Hold}

Hold[1 + 2, 3 + 4, 5 6]

And if you want the inner List back:

expr /. {Hold -> Sequence, List -> Hold} /. Hold[x__] :> Hold[{x}]
Hold[{1 + 2, 3 + 4, 5 6}]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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