10
$\begingroup$

I have a large list, for example,

lis = {x + y, x y, Sin[x] y + Exp[y], x^2 y}

and its elements depend on variables x and y. Later I assign numerical values to x and y

x = {1, 2, 3, 4, 5}
y = {3, 4, 5, 6, 7}

If I run

lis[[1]]

(which is Part[lis, 1]), the whole list lis will be evaluated, and then the first part is taken. But if the list is very large, and I only need the first element, it will waste lots of time to evaluate the rest. Is there a simple way to take and evaluate a specific part of a list without evaluating the rest?

$\endgroup$
  • 1
    $\begingroup$ This could be better example: ClearAll[x, y, z, list]; list = {x, y, z}; x = 1; y = 2; z := Pause[2]; $\endgroup$ – Kuba Nov 23 '15 at 15:24
9
$\begingroup$

You could map Hold over the list:-

lis = {x + y, x y, Sin[x] y + Exp[y], x^2 y};
heldlis = Map[Hold, lis];
x = {1, 2, 3, 4, 5};
y = {3, 4, 5, 6, 7};
ReleaseHold@heldlis[[1]]

{4, 6, 8, 10, 12}

$\endgroup$
  • $\begingroup$ This is the first thought that occurs in my mind:) $\endgroup$ – xyz Nov 23 '15 at 14:23
  • 2
    $\begingroup$ Another possibility in case lis is very large would be to change heldlis = Map[Hold, lis] to heldlis = Hold @@ lis, and accordingly ReleaseHold@heldlis[[1]] to heldlis[[1]]. This proves to be faster for both the creation of heldlis and the retrieving of the sough element from the last evaluation. It also uses less memory. $\endgroup$ – user31159 Nov 24 '15 at 3:43
  • $\begingroup$ @Xavier - heldlis = Hold @@ lis works ok. Then you don't need ReleaseHold; just heldlis[[1]] will suffice. $\endgroup$ – Chris Degnen Nov 24 '15 at 8:51
6
$\begingroup$

Is there a simple way to take and evaluate a specific part of a list without evaluating the rest?

You could use the Rule[] rather than Set[]. For instance,

lis = {x + y, x y, Sin[x] y + Exp[y], x^2 y};

lis[[1]] /.{x -> {1, 2, 3, 4, 5}, y -> {3, 4, 5, 6, 7}}
 {4, 6, 8, 10, 12}
$\endgroup$
6
$\begingroup$

If you define lis before x and y as a plain List you can use the following trick with OwnValues

ClearAll[x, y];
lis = {x + y, x y, Sin[x] y + Exp[y], x^2 y};
x = {1, 2, 3, 4, 5};
y = {3, 4, 5, 6, 7};

Part[Hold@lis /. OwnValues@lis, 1, 1]
(* {4, 6, 8, 10, 12} *)

Indeed, it calculates the first element only:

Part[Hold@lis /. OwnValues@lis, 1, 1] // Trace

(* {{{OwnValues[lis], {HoldPattern[lis] :> {x+y,x y,E^y+y Sin[x],x^2 y}}},
 Hold[lis] /. {HoldPattern[lis]:>{x+y,x y,E^y+y Sin[x],x^2 y}},
 Hold[{x+y,x y,E^y+y Sin[x],x^2 y}]},
 Hold[{x+y,x y,E^y+y Sin[x],x^2 y}][[1,1]], x+y,
 {x,{1,2,3,4,5}}, {y,{3,4,5,6,7}}, {1,2,3,4,5}+{3,4,5,6,7},
 {1+3,2+4,3+5,4+6,5+7}, {1+3,4}, {2+4,6}, {3+5,8}, {4+6,10}, {5+7,12},
 {4,6,8,10,12}} *)
$\endgroup$
0
$\begingroup$

Another way is to store each part of the list using memorization and then call the part you want.

Quit[];

i = 1; (f[i++] = #) & /@ (lis = {x + y, If[x > 0, Pause[5]], 
    Sin[x] y + Exp[y], x^2 y});

Now try this and check the difference in time.

x = 1;
f[1];
lis[[1]];
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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