7
$\begingroup$

If I have a list of associations (listAssoc) with members all having key someKey, how can I generate a new list of associations listAssoc2 that is equal to listAssoc except the values of someKey have all been changed by having some function f applied to their values?

$\endgroup$

5 Answers 5

8
$\begingroup$
MapAt[Sin, #, "somekey"] & /@ listAssoc
$\endgroup$
1
  • 2
    $\begingroup$ If you modify the third argument of MapAt then you won't need to map a pure function: MapAt[f, ascList, {All, Key[someKey]}] $\endgroup$
    – Jason B.
    Dec 30, 2019 at 19:27
8
$\begingroup$

You can also use Query. Using a variation of @kglr's example:

ascList = Table[
    <|a->RandomInteger[100], "someKey"->RandomInteger[100], c->RandomInteger[100]|>,
    5
]

{<|a -> 32, "someKey" -> 16, c -> 90|>, <|a -> 77, "someKey" -> 28, c -> 82|>, <|a -> 39, "someKey" -> 70, c -> 66|>, <|a -> 21, "someKey" -> 79, c -> 32|>, <|a -> 66, "someKey" -> 16, c -> 4|>}

Then:

Query[{"someKey" -> foo}] /@ ascList

{<|a -> 32, "someKey" -> foo[16], c -> 90|>, <|a -> 77, "someKey" -> foo[28], c -> 82|>, <|a -> 39, "someKey" -> foo[70], c -> 66|>, <|a -> 21, "someKey" -> foo[79], c -> 32|>, <|a -> 66, "someKey" -> foo[16], c -> 4|>}

In m_goldberg's deleted answer, he suggests a nice refinement:

Query[All, {"someKey" -> foo}] @ ascList

{<|a -> 88, "someKey" -> foo[78], c -> 98|>, <|a -> 2, "someKey" -> foo[18], c -> 24|>, <|a -> 52, "someKey" -> foo[8], c -> 64|>, <|a -> 7, "someKey" -> foo[96], c -> 73|>, <|a -> 92, "someKey" -> foo[75], c -> 49|>}

$\endgroup$
1
  • $\begingroup$ @m_goldberg I liked your answer, so I included it. If you undelete your answer, I would be happy to remove my addition. $\endgroup$
    – Carl Woll
    Dec 30, 2019 at 18:26
3
$\begingroup$
ascList = Table[<|a -> RandomInteger[100], someKey -> RandomInteger[100], 
   c -> RandomInteger[100]|>, 5]

{<|a -> 44, someKey -> 93, c -> 67|>,
<|a -> 49, someKey -> 44, c -> 85|>,
<|a -> 61, someKey -> 4, c -> 88|>,
<|a -> 38, someKey -> 24, c -> 8|>,
<|a -> 78, someKey -> 87, c -> 44|>}

Normal @ Dataset[ascList][All, {Key[someKey] -> foo}]

{<|a -> 44, someKey -> foo[93], c -> 67|>,
<|a -> 49, someKey -> foo[44], c -> 85|>,
<|a -> 61, someKey -> foo[4], c -> 88|>,
<|a -> 38, someKey -> foo[24], c -> 8|>,
<|a -> 78, someKey -> foo[87], c -> 44|>}

Also

MapIndexed[If[#2[[2, 1]] === someKey, foo@#, #] &, ascList, {2}]

same result

MapIndexed[If[#2[[1, 1]] === someKey, foo@#, #] &] /@ ascList

same result

$\endgroup$
3
$\begingroup$

Use Part assignment:

listAssoc2 = listAssoc;
listAssoc2[[All, Key[someKey]]] = f /@ listAssoc2[[All, Key[someKey]]]
$\endgroup$
2
$\begingroup$

Since V 13.1 we can also use ReplaceAt. To demonstrate its usefulness I create a list with a missing value:

  list =
   {<|"a" -> 32, "b" -> 16, "c" -> 90|>, 
    <|"a" -> 77, "b" -> Missing[], "c" -> 82|>, 
    <|"a" -> 39, "b" -> 70, "c" -> 66|>, 
    <|"a" -> 21, "b" -> 79, "c" -> 32|>, 
    <|"a" -> 66, "b" -> 16, "c" -> 4|>};

ReplaceAt[x_?NumberQ :> x + 10, {All, "b"}] @ list // Dataset

enter image description here

To get the same result with the "classical" Query - method we would have to write:

Query[All, <|#, "b" -> If[NumberQ[#b], #b + 10, Missing[]]|> &] @ list // Dataset

Additional Conditions can be injected easily:

ReplaceAt[x_?NumberQ /; Between[x, {1, 30}] :> x + 10, {All, "b"}] @ list
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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