For example

{a + b} == {c + d} // Thread
(*{a + b == c + d}*)

how to get {a + b} == {c + d} from {a + b == c + d} ?

This is my try

Equal @@ List /@ Join @@ {a + b == c + d}

Are there other ways to do this?

• Map[List, {a + b == c + d}, {2}] – Dr. belisarius Jul 12 '13 at 17:15
• {a + b == c + d} /. f_[x_, y_] :> f[{x}, {y}] (only in special cases) – Kuba Jul 12 '13 at 17:16
• Just for fun: Equal @@ Tuples@{a + b == c + d} => {a + b} == {c + d} – user1066 Jul 12 '13 at 23:47

One way would be

Distribute[{a + b == c + d}, Equal]

Same as

Thread[{a + b == c + d}, Equal]

More universal

{a + b == c + d}/. f_[g_[x_, y_]] -> g[f[x], f[y]]
• Thanks, I'm completely a mess on these. How do you change {a==b,c==d} to {a+c==b+d} again using Thread? – xslittlegrass Jul 12 '13 at 20:08
• @xslittlegrass, If you really need Thread for this, maybe: {Thread[Total@{a == b, c == d}, Equal]}, another way would be: Inner[Plus, Sequence @@ {a == b, c == d}, Equal] – panda-34 Jul 12 '13 at 20:48
• (+1) I like the Thread way. It seems more natural in this case, where threading is basically transposition with different heads. In fact, it seems more universal than the replacement rule, certainly with respect to number of arguments, but also considering that one specifies the head for Thread in the first place, either List by default or explicitly by it optional second argument. – Michael E2 Jul 12 '13 at 21:17

The Thread operation is not completely invertible in all cases, but if we assume that

• only level 1 is to be considered, and
• in the original Thread, all arguments had the same head and length,

then the expression can be unthreaded. Perhaps others can extend this.

Here, in unthread[expr, h], if expr is of the form

f[h[a1, a2,...], h[b1, b2,...],...]

the the result will be

h[f[a1, b1,...], f[a1, b2,...],...]

The default for h is List. Thus unthread[f[h[a1, a2,...],..., h] undoes Thread[h[f[a1, b1,...],...], f].

unthread::tdlen = "Objects of unequal length in  cannot be uncombined. :)";
unthread::head = "Objects in  not all of type .";
unthread[expr_, h_: List] /;
(Length@DeleteDuplicates[Length /@ expr] == 1 ||
(Message[unthread::tdlen, expr]; False)) &&
(DeleteDuplicates[Head /@ List @@ expr] == {h} ||
With[{h2 = Head[expr]}, h @@ h2 @@@ Transpose[List @@ List @@@ expr]];
unthread[expr_, h_] := expr;  (* return expressions that do not satisfy criteria *)

Examples

unthread[{a + b == c + d}, Equal]
(* {a + b} == {c + d} *)

unthread[g[f[a, aa], f[b, bb], f[c, cc]], f]
(* f[g[a, b, c], g[aa, bb, cc]] *)

unthread[g[f[a, aa], f[b, bb], f[c, cc, ccc]], f]
(* unthread::tdlen: Objects of unequal length in g[f[a,aa], f[b,bb], f[c,cc,ccc]]
cannot be uncombined. :) *)
(* g[f[a, aa], f[b, bb], f[c, cc, ccc]] *)

unthread[g[f[a, aa], f[b, bb], h[c, cc]], f]
(* unthread::head: Objects in g[f[a,aa], f[b,bb], h[c,cc]] not all of type f. *)
(* g[f[a, aa], f[b, bb], h[c, cc]] *)

An example in which two different Thread operations yield the same output, which shows Thread is not completely reversible.

Thread[f[g[a, b, c], g[aa, bb, cc], d], g]
(* g[f[a, aa, d], f[b, bb, d], f[c, cc, d]] *)

Thread[f[g[a, b, c], g[aa, bb, cc], g[d, d, d]], g]
(* g[f[a, aa, d], f[b, bb, d], f[c, cc, d]] *)