close

Function Repository Resource:

LookupPart

Source Notebook

Get part of an expression or return a default value if it doesn’t exist

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["LookupPart"][expr,part]

returns expr[[part]] if it exists and a Missing object otherwise.

ResourceFunction["LookupPart"][expr,{p1,p2,}]

gives the list of parts {expr[[p1]],expr[[p2]],}.

ResourceFunction["LookupPart"][expr,Sequence[p1,p2,]]

gives expr[[p1,p2,]] if it exists and a Missing object otherwise.

ResourceFunction["LookupPart"][expr,parts,default]

gives default if the specified part is not found.

ResourceFunction["LookupPart"][parts]

represents an operator form of LookupParts that can be applied to an expression.

Details and Options

In ResourceFunction["LookupPart"][expr,part,default], default is only evaluated if part does not correspond to a subexpression in expr.
Part 0 of an expression is its head.
ResourceFunction["LookupPart"] supports Span specifications for parts, which include:
m;;part m through the end
;;nfrom the beginning to part n
;;,jcolumn j
m1;;n1,m2;;n2submatrix
ResourceFunction["LookupPart"] has the attributes SequenceHold and HoldRest.
Since ResourceFunction["LookupPart"] has the SequenceHold attribute, wrapping parts in Sequence can be used to retrieve nested values.
The form "key" can be used as a part specification to extract a value from an association whose key is a string. Key[k] can be used to extract values with any keys.
"key" and Key[k] can appear anywhere in the specification of parts.

Examples

Basic Examples (9) 

Look up part of an expression:

In[1]:=
ResourceFunction["LookupPart"][{a, b}, 1]
Out[1]=
Image

If the specified part is not found, a Missing object is returned:

In[2]:=
ResourceFunction["LookupPart"][{a, b}, 3]
Out[2]=
Image

Providing a third argument allows the default value to be provided:

In[3]:=
ResourceFunction["LookupPart"][{a, b}, 3, c]
Out[3]=
Image

When the part is present, the default is not evaluated:

In[4]:=
ResourceFunction["LookupPart"][{a, b}, 1, Print["not found"]]
Out[4]=
Image

Look up multiple parts:

In[5]:=
ResourceFunction["LookupPart"][{a, b, c}, {1, 3, 5}]
Out[5]=
Image
In[6]:=
ResourceFunction["LookupPart"][{a, b, c}, {1, 3, 5}, xx]
Out[6]=
Image

Use Span syntax to look up a sequence of parts:

In[7]:=
ResourceFunction["LookupPart"][{a, b, c}, 2 ;; 3]
Out[7]=
Image
In[8]:=
ResourceFunction["LookupPart"][{a, b, c}, 2 ;; 5]
Out[8]=
Image
In[9]:=
ResourceFunction["LookupPart"][{a, b, c}, 2 ;; 5, xx]
Out[9]=
Image

Count from the end of the list:

In[10]:=
ResourceFunction["LookupPart"][{a, b, c}, -1]
Out[10]=
Image
In[11]:=
ResourceFunction["LookupPart"][{a, b, c}, -5]
Out[11]=
Image
In[12]:=
ResourceFunction["LookupPart"][{a, b, c}, -5, xx]
Out[12]=
Image

Use UpTo in a Span specification:

In[13]:=
ResourceFunction["LookupPart"][{a, b, c}, 2 ;; UpTo[5]]
Out[13]=
Image
In[14]:=
ResourceFunction["LookupPart"][{a, b, c, d, e, f}, 2 ;; UpTo[5]]
Out[14]=
Image

Use the operator form:

In[15]:=
ResourceFunction["LookupPart"][1][{a, b, c}]
Out[15]=
Image
In[16]:=
ResourceFunction["LookupPart"][-1][{a, b, c}]
Out[16]=
Image
In[17]:=
ResourceFunction["LookupPart"][1 ;; 2][{a, b, c}]
Out[17]=
Image
In[18]:=
ResourceFunction["LookupPart"][5][{a, b, c}]
Out[18]=
Image

Scope (9) 

Using zero as the part specification corresponds to the head of an expression:

In[19]:=
ResourceFunction["LookupPart"][a + b, 0]
Out[19]=
Image

Look up a nested part:

In[20]:=
ResourceFunction["LookupPart"][{{a, b}, {c, d}}, Sequence[2, 1]]
Out[20]=
Image
In[21]:=
ResourceFunction["LookupPart"][{{a, b}, {c, d}}, Sequence[2, 3]]
Out[21]=
Image
In[22]:=
ResourceFunction["LookupPart"][{{a, b}, {c, d}}, Sequence[2, 3], xx]
Out[22]=
Image

Get multiple nested parts:

In[23]:=
ResourceFunction[
 "LookupPart"][{{a, b}, {c, d}}, {Sequence[2, 1], Sequence[2, 3], Sequence[1, 1]}]
Out[23]=
Image
In[24]:=
ResourceFunction[
 "LookupPart"][{{a, b}, {c, d}}, {Sequence[2, 1], Sequence[2, 3], Sequence[1, 1]}, xx]
Out[24]=
Image

Use a mix of part specifications:

In[25]:=
ResourceFunction[
 "LookupPart"][{{a, b}, {c, d}}, {Sequence[2, 1], 2, Sequence[1, 1, 0]}]
Out[25]=
Image

Get the second column of a matrix:

In[26]:=
ResourceFunction["LookupPart"][{{a, b, c}, {d, e, f}, {g, h, i}}, Sequence[All, 2]]
Out[26]=
Image

Get part of an association by key:

In[27]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, Key[a]]
Out[27]=
Image
In[28]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, Key[c]]
Out[28]=
Image

Get part of an association by position:

In[29]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, 2]
Out[29]=
Image
In[30]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, 5]
Out[30]=
Image

Get a nested part of an association:

In[31]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> <|c -> 3|>|>, Sequence[Key[b], Key[c]]]
Out[31]=
Image

Or equivalently:

In[32]:=
ResourceFunction["NestedLookup"][<|a -> 1, b -> <|c -> 3|>|>, {b, c}]
Out[32]=
Image

Use Unevaluated to look up part of the expression before it evaluates:

In[33]:=
ResourceFunction["LookupPart"][Unevaluated[1 + 2 + 3], -1]
Out[33]=
Image

Only the returned part will evaluate:

In[34]:=
ResourceFunction["LookupPart"][Unevaluated[Echo[1] + Echo[2]], -1]
Image
Out[34]=
Image
In[35]:=
ResourceFunction["LookupPart"][Unevaluated[Echo[1] + Echo[2]], 3]
Out[35]=
Image

Applications (1) 

Create variants of First and Last that return a Missing object when the list is empty:

In[36]:=
first = ResourceFunction["LookupPart"][1]
Out[36]=
Image
In[37]:=
last = ResourceFunction["LookupPart"][-1]
Out[37]=
Image
In[38]:=
first[{1, 2, 3}]
Out[38]=
Image
In[39]:=
first[{}]
Out[39]=
Image
In[40]:=
last[{1, 2, 3}]
Out[40]=
Image
In[41]:=
last[{}]
Out[41]=
Image

Properties and Relations (9) 

LookupPart operates on the FullForm of expressions:

In[42]:=
ResourceFunction["LookupPart"][x/y, 2]
Out[42]=
Image
In[43]:=
FullForm[x/y]
Out[43]=
Image

LookupPart returns the default value instead of failing if the first argument is atomic:

In[44]:=
ResourceFunction["LookupPart"]["Is this fine?", 1, "This is fine."]
Out[44]=
Image

Compare to Part:

In[45]:=
Part["This is not.", 1]
Image
Out[45]=
Image

LookupPart[0] is equivalent to Head:

In[46]:=
ResourceFunction["LookupPart"][0][a + b]
Out[46]=
Image
In[47]:=
Head[a + b]
Out[47]=
Image

LookupPart[Sequence[]] is equivalent to Identity:

In[48]:=
ResourceFunction["LookupPart"][Sequence[]][a + b]
Out[48]=
Image

LookupPart has the SequenceHold attribute:

In[49]:=
ResourceFunction["LookupPart"][a + b, Sequence[]]
Out[49]=
Image

Part does not, so these are equivalent:

In[50]:=
Part[a + b, Sequence[]]
Out[50]=
Image
In[51]:=
Part[a + b]
Out[51]=
Image

Using a Sequence as a part specification is similar to a Fold over the parts:

In[52]:=
list = {{{a, b}, {c, d}}, {{e, f}, {g, h}}}
Out[52]=
Image
In[53]:=
ResourceFunction["LookupPart"][list, Sequence[2, 1, 2]]
Out[53]=
Image
In[54]:=
Fold[ResourceFunction["LookupPart"], list, {2, 1, 2}]
Out[54]=
Image

When the default value is not specified, LookupPart defaults to a Missing object that contains elements corresponding to what would be issued in a message when using Part:

In[55]:=
ResourceFunction["LookupPart"][{1, 2, 3}, 5]
Out[55]=
Image
In[56]:=
Part[{1, 2, 3}, 5]
Image
Out[56]=
Image
In[57]:=
ResourceFunction["LookupPart"][{{a, b}, {c, d}}, Sequence[2, 3]]
Out[57]=
Image
In[58]:=
Part[{{a, b}, {c, d}}, Sequence[2, 3]]
Image
Out[58]=
Image

Specifying part 0 always* succeeds without evaluating the third argument:

In[59]:=
ResourceFunction["LookupPart"][x, 0, Print["You (almost certainly) can't get here."]]
Out[59]=
Image

* Unless it doesn’t:

In[60]:=
ResourceFunction["LookupPart"][TagSetDelayed[nope, 
Blank[][nope, 0, 
Pattern[default, 
Blank[]]], default]; nope, 0, Print["What have you done?"]]
Image

LookupPart has the NHoldAll attribute, so its operator form won’t be affected by N:

In[61]:=
N[{ResourceFunction["LookupPart"][1], {{1, 2, 3}}}]
Out[61]=
Image
In[62]:=
Apply @@ %
Out[62]=
Image

Possible Issues (2) 

Unlike Lookup, the second argument of LookupPart behaves like the second argument of Part, so keys to associations must be wrapped in Key:

In[63]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, Key[a]]
Out[63]=
Image
In[64]:=
Part[<|a -> 1, b -> 2|>, Key[a]]
Out[64]=
Image

Attempting to use the key directly results in an error:

In[65]:=
ResourceFunction["LookupPart"][<|a -> 1, b -> 2|>, a]
Image
Out[65]=
Image

This is also true for Part:

In[66]:=
Part[<|a -> 1, b -> 2|>, a]
Image
Out[66]=
Image

However, if the keys are strings, Key is not necessary:

In[67]:=
ResourceFunction["LookupPart"][<|"a" -> 1, "b" -> 2|>, "a"]
Out[67]=
Image
In[68]:=
Part[<|"a" -> 1, "b" -> 2|>, "a"]
Out[68]=
Image

When using Span or All part specifications, LookupPart does not return partial results if any part of the sequence is missing:

In[69]:=
list = Table[Subscript[f, x, y], {x, 4, 1, -1}, {y, x}]
Out[69]=
Image
In[70]:=
ResourceFunction["LookupPart"][list, Sequence[All, 3]]
Out[70]=
Image

This behavior is consistent with Part:

In[71]:=
Part[list, Sequence[All, 3]]
Image
Out[71]=
Image

In this case, use of Map can yield partial results:

In[72]:=
Map[ResourceFunction["LookupPart"][3], list] // DeleteMissing
Out[72]=
Image

Neat Examples (1) 

Create a new lookup function with a neat default value:

In[73]:=
birdLookup[expr_, part_] := ResourceFunction["LookupPart"][expr, part, ResourceFunction["BirdSay"][
    Row[{"The expression ", expr, " does not have part ", part, "."}]]];
In[74]:=
birdLookup[{a, b}, 2]
Out[74]=
Image
In[75]:=
birdLookup[{a, b}, 3]
Out[75]=
Image

Version History

  • 1.0.0 – 15 October 2019

Related Resources

License Information