13

I have a huge list with huge sublists of the form

list={{a,b,c,d},{e,f,g,h},{i,j,k,l}}

I am looking for a way to manipulate these sublists based on the positions of the elements. Something like

list/.{j_,k_,l_,m_}->{j-1,k,l,m}

but without having to write the whole pattern. Is there any way to specify such manipulation based on the position of the element? Something like

list/.#[[1]] & -> #[[1]] - 1 &

that would work?

Kuba
  • 136,707
  • 13
  • 279
  • 740
Sos
  • 2,168
  • 16
  • 31

10 Answers10

16

You could use: MapAt:

MapAt[ # - 1 &, list, {All, 1}]
{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

or Apply at the first level (shorthand @@@) (see also SlotSequence, shorthand ##n):

{#1 - 1, ##2}& @@@ list
Artes
  • 57,212
  • 12
  • 157
  • 245
  • Your first answer, together with @andre's answer, seems to be the most robust since I can specify the position to to the subtraction, without having to do it only in the 1st position. – Sos Feb 18 '14 at 16:30
15

This is quite neat:

list[[;; , 1]]--
Kuba
  • 136,707
  • 13
  • 279
  • 740
  • 2
    It yields {a, e, i} for the list in the OP so one has to evaluate list twice to get the result of list /. {j_, k_, l_, m_} -> {j - 1, k, l, m}, since it changes list I find it's rather a drawback. – Artes Feb 18 '14 at 10:30
  • 1
    @Artes Indeed. Well, after this list is updated, the method you want to use depends of what OP needs at the end. – Kuba Feb 18 '14 at 10:33
7

If you write

list[[All, 1]] = list[[All, 1]] - 1

list will be updated with the new values of the first element of each sublist.

C. E.
  • 70,533
  • 6
  • 140
  • 264
6

Maybe

ReplacePart[list, (x : {_, 1}) :> (Extract[list, x] - 1)]  

?

The positions of the elements are specified by the pattern on the indices : {_,1}

{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

andre314
  • 18,474
  • 1
  • 36
  • 69
5

That's a prime example to use Threaded which was introduced in v13.1

list = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}};
list + Threaded[{-1, 0, 0, 0}]

{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

bmf
  • 15,157
  • 2
  • 26
  • 63
5

You might be able to use this rule-based method

Replace[list, {f_, r___} -> {f - 1, r}, {1}]
{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

or something similar. This will work for any sublist length.

list2 = {{a, b, c, d}, {e, f, g}, {h}};
Replace[list2, {f_, r___} -> {f - 1, r}, {1}]
{{-1 + a, b, c, d}, {-1 + e, f, g}, {-1 + h}}

More generally

munge[func_, data_] := Replace[data, {f_, r___} :> {func@f, r}, {1}]
munge[# - 1 &, list]
{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}
m_goldberg
  • 107,779
  • 16
  • 103
  • 257
  • I had been trying to play with replacement rules but to no avail, but now I see why. Btw, would there be a way to specify the position in which the replacement would have to be made? e.g. if I wanted to apply the rule to each element in position 37 of sublists with 100 elements? – Sos Feb 18 '14 at 16:26
  • Nevermind, I guess that would have to be something similar to what @andre answered – Sos Feb 18 '14 at 16:28
3
list = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}};

We can also use ReplaceAt (new in 13.1)

ReplaceAt[x_ :> x - 1, {All, 1}] @ list

{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

One of its advantages is that we can easily add conditions:

ReplaceAt[x_ /; x =!= e :> x - 1, {All, 1}] @ list

{{-1 + a, b, c, d}, {e, f, g, h}, {-1 + i, j, k, l}}

To update list inline we can employ ApplyTo (new in 12.2)

list //= ReplaceAt[x_ :> x - 1, {All, 1}];

list

{{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}}

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

Using Cases:

list = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}};

Cases[list, x_ :> {-1 + First@x, Sequence @@ Rest@x}]

({{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}})

Edit Or as @eldo suggests, an equivalent way of doing it using Splice instead of Sequence:

Cases[list, x_ :> {-1 + First@x, Splice@Rest@x}] (*Thanks, eldo!*)

({{-1 + a, b, c, d}, {-1 + e, f, g, h}, {-1 + i, j, k, l}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
2
list + ConstantArray[{-1,0,0,0},3]

(* {{-1+a,b,c,d},{-1+e,f,g,h},{-1+i,j,k,l}} *)
user1066
  • 17,923
  • 3
  • 31
  • 49
0

Using SubetMap:

Clear["Global`*"];
list = {{a, b, c, d}, {e, f, g, h}, {i, j, k, l}};
SubsetMap[# - 1 &, list, {All, 1}] // Column

Result:

enter image description here

Syed
  • 52,495
  • 4
  • 30
  • 85