4

I have a list in the form {{a, 1}, {b, 2}, {c, 3}}.

Let's say I want to operate a transformation on all the second elements of each sublist, but this transformation is a function of them all together. As an example I want to Standardize them.

At the moment I've implemented this with Transpose.

mylist = {{a, 1}, {b, 2}, {c, 3}};
newlist = Transpose[{mylist[[All, 1]], Standardize[mylist[[All, 2]]]}]

and the output is correctly

{{a, -1}, {b, 0}, {c, 1}}

I find this a little cumbersome, this approach can become complicated and hard to read sometimes. Isn't there a more natural way?

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
CupiDio
  • 439
  • 2
  • 9
  • 2
    You could do newlist = mylist; newlist[[All, 2]] = Standardize[newlist[[All, 2]]];, but I don't consider it any more natural than what you have. – J. M.'s missing motivation Jun 10 '13 at 15:30
  • I am positive this question is a duplicate, though perhaps the original is on StackOverflow. I'd appreciate help finding it. – Mr.Wizard Jun 10 '13 at 15:32
  • This is related but it does not expressly describe passing the entire column to the function; I know there is a question that does. – Mr.Wizard Jun 10 '13 at 15:37
  • 1
    Another slight variation (but hardly more natural either): MapAt[Standardize, #\[Transpose], 2]\[Transpose] &@mylist – user1066 Jun 10 '13 at 16:54
  • Duh, deleting my remark, which is just a repeat of what 0x4A4D said. But I like that method. – Todd Gayley Jun 10 '13 at 18:18

5 Answers5

3

I'd suggest...

Apply[Transpose[{#1,Standardize[#2]}]&,Transpose[mylist]]
Ymareth
  • 4,741
  • 20
  • 28
3

This is a good case for SubsetMap (new in 12.0)

list = {{a, 1}, {b, 2}, {c, 3}};

SubsetMap[Standardize, list, {All, 2}]

{{a, -1}, {b, 0}, {c, 1}}

eldo
  • 67,911
  • 5
  • 60
  • 168
3

Another way is to use MapAt:

list = {{a, 1}, {b, 2}, {c, 3}};

Transpose@MapAt[Standardize, Transpose@#, {2}] &@list

({{a, -1}, {b, 0}, {c, 1}})

Or using ReplaceAt:

Transpose@ReplaceAt[Transpose@#, _ -> Standardize@*List, {2, 0}] &@list

({{a, -1}, {b, 0}, {c, 1}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
2

Here's a small variation on the solutions proposed in the comments:

Thread[{First[Thread[myList]], Standardize[Last[Thread[myList]]]}]
bill s
  • 68,936
  • 4
  • 101
  • 191
2

Using ReplacePart

index = 1;
ReplacePart[list, {_, 2} :> Standardize[list[[All, 2]]][[index++]]]

Edit: an equivalent way of writing the above is, thanks to @eldo

ReplacePart[list, {i_, 2} :> Standardize[list[[All, 2]]][[i]]]

Or using ThroughOperator introduced in 2022

Variables@list;
Flatten[ResourceFunction["ThroughOperator"][{Standardize}]@
   list[[All, 2]]];
Thread[{%%, %}]
bmf
  • 15,157
  • 2
  • 26
  • 63