Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

There are a number of questions on this site about "threading" including several relating to uneven (ragged) lists. However, none that I could find deal with the full functionality of Thread but instead things like MapThread, or the ragged transpose of Flatten[expr, {2}].

Thread operates:

  • Inside held expressions without errant evaluation

  • On arbitrary heads as specified with the second parameter

  • By distributing singlets across all subexpressions

  • On only the first n arguments (subexpressions) if given as third parameter

For example:

expr = Hold[qq[2 + 2, 1/0, 8/4], qq[1, 2, 3], Sqrt[2 + 2]];

Thread[expr, qq]

Thread[expr, qq, 1]
qq[Hold[2 + 2, 1, Sqrt[2 + 2]], Hold[1/0, 2, Sqrt[2 + 2]], Hold[8/4, 3, Sqrt[2 + 2]]]

qq[Hold[2 + 2, qq[1, 2, 3], Sqrt[2 + 2]], Hold[1/0, qq[1, 2, 3], Sqrt[2 + 2]], 
   Hold[8/4, qq[1, 2, 3], Sqrt[2 + 2]]]

All of this breaks if we change qq[1, 2, 3] to qq[1, 2].

What is the most efficient way to extend Thread to ragged subexpressions?

share|improve this question

3 Answers 3

This is my take on the pad, thread normally, then remove padding approach.

fred[expr_, head_: List, seq_: All] := 
 Module[{myhold, maxlength, dummy, paddedexpr}, 
  SetAttributes[myhold, HoldAllComplete];
  maxlength = Max@Cases[expr, head[args___] :> Length@Hold@args, {1}];
  paddedexpr = Replace[expr, head[args___] :>
     RuleCondition@PadRight[myhold@args, maxlength, dummy], {1}];
  DeleteCases[Thread[paddedexpr, myhold, seq], dummy, -1] /. myhold -> head]
share|improve this answer
    
Much more polished :) I didn't know Pad.. worked on arbitrary heads. Sweet. –  mfvonh Jun 9 at 22:05
1  
+1, I would have done something quite similar. I think the Replace level better be {1} in case the whole expression is wrapped in head. –  Rojo Jun 11 at 0:53
    
Also, there's the small issue of definitions that didn't match now matching with the padded dummy arguments. Perhaps keeping the myhold and some other one for the head of heads, and replacing them back after the threading? Not sure if I am thinking straight, and I don't have MMA to try stuff –  Rojo Jun 11 at 0:53
    
@Rojo, thanks - good points. –  Simon Woods Jun 11 at 8:34

// timidly raises hand

Maybe this approach?

ClearAll[Thread2];
SetAttributes[Thread2, HoldAllComplete];
Thread2[expr_, etc___] :=
  DeleteCases[
   Thread[
    With[
     {max = Length /@ {expr} // Max},
     Quiet[
      Replace[
       expr,
       h_[c___] /; 1 < Length@{c} < max :> 
         RuleCondition[
           h[c,
             Sequence @@ ConstantArray[EatMe, max - Length@{c}]]],
       {1}]]], etc], 
   EatMe, 3];

expr = Hold[qq[2 + 2, 1/0, 8/4], qq[1, 2, 3], Sqrt[2 + 2]];    
Thread2[expr, qq]
Thread2[expr, qq, 1]
qq[Hold[2 + 2, 1, Sqrt[2 + 2]], Hold[1/0, 2, Sqrt[2 + 2]], Hold[8/4, 3, Sqrt[2 + 2]]]

qq[Hold[2 + 2, qq[1, 2, 3], Sqrt[2 + 2]], Hold[1/0, qq[1, 2, 3], Sqrt[2 + 2]],  Hold[8/4, qq[1, 2, 3], Sqrt[2 + 2]]]
expr2 = Hold[qq[2 + 2, 1/0, 8/4], qq[1, 2], Sqrt[2 + 2]];
Thread2[expr2, qq]
Thread2[expr2, qq, 1]
qq[Hold[2 + 2, 1, Sqrt[2 + 2]], Hold[1/0, 2, Sqrt[2 + 2]], Hold[8/4, Sqrt[2 + 2]]]

qq[Hold[2 + 2, qq[1, 2], Sqrt[2 + 2]], Hold[1/0, qq[1, 2], Sqrt[2 + 2]], Hold[8/4, qq[1, 2], Sqrt[2 + 2]]]
share|improve this answer
    
There is no need to be timid. Thanks for answering. I had my own ideas for implementing this but I wasn't feeling very imaginative so I wanted to see how others would do it. –  Mr.Wizard Jun 9 at 7:30
    
Thread2[{{1, 2, 3, 4, 5}, {6, 7, 8}}] gives a Thread::tdlen error. –  Simon Woods Jun 9 at 12:43

If I understand the question correctly, you are looking to use Thread on ragged subexpressions. I will give my solution on ragged list:

list = {{a, b}, {c, f, r, t}, {t, y, k}};
length = Length[#] & /@ list;
max = Max@length;
list2 = Join[#, ConstantArray[0, max - Length[#]]] & /@ list;
list3 = Thread[List @@ list2];
list4 = DeleteCases[list3, _ 0, \[Infinity]];
f @@@ list4

(*    {f[a, c, t], f[b, f, y], f[r, k], f[t]}*)
share|improve this answer
    
Is this intended to be only an illustration? Will this handle the additional parameters of Thread? I think you would also need to avoid accidentally deleting zeros that were present in the original expression. By the way, you don't need to write Length[#] & /@ list -- Length is already a function, so write: Length /@ list. :-) –  Mr.Wizard Jun 9 at 7:34
    
@Mr. Wizard, thank you for your input. regarding deleting zero, this can be changed to be any value that is not showing in the ragged list. –  Algohi Jun 9 at 15:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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