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$
2
  • $\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$ Commented Sep 9, 2016 at 1:40
  • $\begingroup$ Extract[traj, {{All, 1}, {All, 2, 2}}] works as desired in version 13.3 (perhaps in earlier versions too). $\endgroup$ Commented Jan 5, 2024 at 7:48

6 Answers 6

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$ Commented Sep 9, 2016 at 2:33
1
$\begingroup$
list = {{t1, {x1, y1}, {vx1, vy1}}, {t2, {x2, y2}, {vx2, vy2}}, {t3, {x3, y3}, {vx3, vy3}}}; 

I would probably use

Cases[{a_, b_, _} :> {a, b[[2]]}] @ list 

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

$\endgroup$
1
$\begingroup$
list = { {t1, {x1, y1}, {vx1, vy1}}, {t2, {x2, y2}, {vx2, vy2}}, {t3, {x3, y3}, {vx3, vy3}} }; 

Using Most and Last:

f = Function[x, Last @@@ Most@x]; f /@ list (*{{t1, y1}, {t2, y2}, {t3, y3}}*) 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.