4
$\begingroup$

I've got a data structure that consists of a long list of triples; each triple consists of a number, a two-element pair, and a two-element pair. Symbolically, I can represent this data structure as {{t1, {x1, y1}, {vx1, vy1}}, {t2, {x2, y2}, {vx2, vy2}}, ...}.

I want to extract just the tN and yN values as pairs, to end up with a list like this: {{t1, y1}, {t2, y2}, ...}. I can think of several ways to do this, including: pulling the tN out into one variable, the yN out into another, packaging the two together into a list, and transposing; or, flattening and using Part. However, the outermost list is likely to be very long, and I want to minimize list rearrangement and copying.

It seems like Extract should do the job. And it would, too, except that it throws an error whenever I try to use All as a position specification. When I try this:

traj = {{t1, {x1, y1}, {vx1, vy1}}, {t2, {x2, y2}, {vx2, vy2}}, {t3, {x3, y3}, {vx3, vy3}}};
Extract[traj, {{All, 1}, {All, 2, 2}}]

I get a "Position specification… is not applicable" error. The same thing happens if I try the ;; syntax. However, the following work (although they only produce one pair, not the entire list of pairs):

Extract[traj, {{1, 1}, {1, 2, 2}}]
(* ==> {t1, y1} *)

Extract[traj, {{-1, 1}, {-1, 2, 2}}]
(* ==> {t3, y3} *)

The best solution I've come up with so far is:

Extract[traj, {{#, 1}, {#, 2, 2}}] & /@ Range[Length[traj]]

But the question remains: Is there no way to make Extract take All, or something that has the equivalent functionality? I am flabbergasted that Extract differs from Part in this one small but important way.

$\endgroup$
1
  • $\begingroup$ What an interesting variety of solutions! I accepted @chuy's because I find it the most transparently readable (especially with infix notation for Map). I admit I haven't done careful timing comparisons yet for performance. $\endgroup$
    – ibeatty
    Sep 9, 2016 at 1:40

4 Answers 4

4
$\begingroup$

Yet another way using the operator form of Extract:

Map[Extract[{{1}, {2, 2}}], traj]
(* {{t1, y1}, {t2, y2}, {t3, y3}} *)
$\endgroup$
4
$\begingroup$

Use destructuring.

helper[{t_, {_, y_}, _}] := {t, y}
helper /@ traj

{{t1, y1}, {t2, y2}, {t3, y3}}

$\endgroup$
2
$\begingroup$

I would approach this with Part (shorthand [[ ]]) rather than Extract:

Thread[{traj[[All, 1]], traj[[All, 2, 2]]}]
{{t1, y1}, {t2, y2}, {t3, y3}}
$\endgroup$
1
$\begingroup$

MapAt is the only function I know that allows a list position to contain All. You could exploit that fact:

Reap[MapAt[Sow, traj, {{All, 1}, {All, 2, 2}}]][[2, 1]]

However, I like the following workaround better:

traj[[Sequence @@ #]] & /@ {{All, 1}, {All, 2, 2}}
$\endgroup$
1
  • 2
    $\begingroup$ Transpose[traj[[##]] & @@@ {{All, 1}, {All, 2, 2}}] $\endgroup$ Sep 9, 2016 at 2:33

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.