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?

  • 2
    $\begingroup$ Map[List, {a + b == c + d}, {2}] $\endgroup$ – Dr. belisarius Jul 12 '13 at 17:15
  • $\begingroup$ {a + b == c + d} /. f_[x_, y_] :> f[{x}, {y}] (only in special cases) $\endgroup$ – Kuba Jul 12 '13 at 17:16
  • $\begingroup$ Just for fun: Equal @@ Tuples@{a + b == c + d} => {a + b} == {c + d} $\endgroup$ – 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]]
  • $\begingroup$ Thanks, I'm completely a mess on these. How do you change {a==b,c==d} to {a+c==b+d} again using Thread? $\endgroup$ – xslittlegrass Jul 12 '13 at 20:08
  • $\begingroup$ @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] $\endgroup$ – panda-34 Jul 12 '13 at 20:48
  • $\begingroup$ (+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. $\endgroup$ – 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::usage = "unthread[f[args], h]  \"unthreads\"  f  over  args  each with head  h";
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} ||
       (Message[unthread::head, expr, h]; False)) := 
  With[{h2 = Head[expr]}, h @@ h2 @@@ Transpose[List @@ List @@@ expr]];
unthread[expr_, h_] := expr;  (* return expressions that do not satisfy criteria *)


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]] *)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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