# Apply at indices

Given:

• a blackbox function $$\f : \mathbb N \to \mathbb N\$$,
• a list of positive integers $$\L\$$, and
• a list of indices $$\I\$$,

apply $$\f(x)\$$ to the elements of $$\L\$$ at the indices specified in $$\I\$$.

For example, $$\f(x) = x^2, L = [7, 6, 3, 9, 1, 5, 2, 8, 4]\$$ and $$\I = [3, 5, 8]\$$ (using 1 indexing), we apply $$\f(x)\$$ to the 3rd, 5th and 8th elements, yielding $$\[7, 6, 9, 9, 1, 5, 2, 64, 4]\$$

You may use 0 or 1 indexing for $$\I\$$. The elements of $$\I\$$ will be unique (there will be no duplicates), the maximum element of $$\I\$$ will never exceed the length of $$\L\$$ (or the length of $$\L\$$ minus 1, if using 0 indexing) and the minimum will never be below 1 (or 0, for 0 indexing).

Neither $$\I\$$ nor $$\L\$$ will ever be empty. $$\f\$$ will always return a positive integer, and will always take a single positive integer. $$\L\$$ may be in any order, however, you may decide if $$\I\$$ is in any specific order (e.g. sorted ascending).

This is , so the shortest code in bytes

## Test cases

f(x)
L
I (using 1 indexing)
out

f(x) = x²
[14, 14, 5, 15, 15, 10, 13, 9, 3]
[1, 3, 4, 5, 6, 7]
[196, 14, 25, 225, 225, 100, 169, 9, 3]

f(x) = x+1
[7, 12, 14, 6]
[1, 2, 3, 4]
[8, 13, 15, 7]

f(x) = σ₀(x)+x
[13, 11, 9, 15, 16, 16, 16, 11, 6, 4]
[2, 4, 6, 8, 10]
[13, 13, 9, 19, 16, 21, 16, 13, 6, 7]


where $$\\sigma_0(x)\$$ is the number of divisors function.

This is a builtin in Jelly. This is a program where you can modify the function $$\f\$$ in the Header, and it will generate a random L, I then out on separate lines. The final test case is prefilled into the Header.

• I know this is a builtin in multiple languages (Jelly, J and APL come to mind), so I encourage languages where this is a builtin to also include a non-builtin answer May 5 at 1:56
• Out of interest, how does this work in Jelly? Can't Jelly atoms only work with up to two arguments? May 5 at 2:02
• @RedwolfPrograms Jelly uses it's standard functional-programming I/O format and takes $f$ as the first link. We then use the ¦ quick, which does exactly as the task asks for, using Ç (previous link) as $f$, and ⁹ to indicate that we use I as the indices link, to result in Ç⁹¦ May 5 at 2:05
• May I be a Set object instead of a List?
– user
May 5 at 13:00
• @user Yep, that's fine May 5 at 13:00

# Scratch 3, 16 13 blocks

Scratch functions can't return, so the function f must edit variable x.

• 134 bytes, or 122 bytes if deleting "I" is acceptable. FYI, in scratchblocks2 notation, your script is 136 bytes. scratch.mit.edu/projects/525982055 May 5 at 13:53

# Python 3, 38 bytes

def f(p,a,i):
for q in i:a[q]=p(a[q])


Try it online!

-16 bytes using in-place thanks to dingledooper

# Python 3, 51 bytes

def f(p,a,i):exec("a[i.pop(0)]=p(a[i[0]]);"*len(i))


Try it online!

Inlining with exec does not make it any shorter. But oh well, it was an idea :P

• The obvious solution of modifying the input in-place should be substantially shorter (like for x in i:a[x]=p(a[x])). May 5 at 2:47
• @dingledooper ah right, ofc. we're allowed to do that. thanks May 5 at 2:49

# tinylisp, 104 bytes

(d g(q((L I F _)(i L(c(i(e(h I)_)(F(h L))(h L))(g(t L)(i(e(h I)_)(t I)I)F(a _ 1)))L
(q((F L I)(g L I F 0


The solution is the unnamed lambda function represented by the second line. Uses 0-indexing. Requires that the list of indexes be sorted ascending. Try it online!

### Explanation

Our approach is to define a helper function g that takes a fourth argument representing the current index. Then we walk through the list recursively, incrementing the index each time. If the current index matches the head of the list of indices, we call the function on the head of the list of values and cons the result to the recursive call; otherwise, we cons the value unchanged.

Ungolfed:

(load library)
(def _helper
(lambda (func ls indices index)
(if ls
(cons
(_helper func
(tail ls)
(tail indices)
indices)
nil)))
(def apply-at-indices
(lambda (func ls indices) (_helper func ls indices 0)))


# Jelly, 6 bytes

Çṛ¡"Ṭ}


For the sake of not leaving anything too important in the comments, the built-in solution is Ç€⁹¦.

   "      For each element of the left argument and each corresponding element of
Ṭ}    a list of ones at the indices in the right argument and zeroes elsewhere,
Ç         apply the given function to the left element
¡       a number of times equal to
ṛ        the right element.
"      (For elements of the left argument past the end of the right argument, leave them unchanged.)

• Strictly speaking, the built-in solution is Ç€⁹¦ as required by certain black-box function implementations, for example this function (which implements triangular numbers in a way that vectorises differently). May 5 at 11:45
• @JonathanAllan Ah, I always forget that ¦ delegates completely to implicit vectorization--or lack thereof May 5 at 12:29

# JavaScript (V8), 31 bytes

(a,g,p)=>p.map(i=>a[i]=g(a[i]))


Try it online!

Produces output by modifying the input array in place.

• Why check a[i]?
– l4m2
May 5 at 4:52
• I didn't know we were allowed to not return the result (return something else) when using a function.. is it a bit like not displaying the result when using a full program? May 5 at 7:32
• @l4m2 I hadn't realized the test cases were 1-indexed, so I though invalid indices could be passed. I'll fix that, thanks! May 5 at 12:36
• @Kaddath This output method is allowed by default. May 5 at 14:12
• OK, I was not contesting the answer, just that I didn't know.. but I reckon it feels weird to me, it's like answering to a question with a full program that displays something else than asked and saying "the result is in this variable" May 5 at 14:38

# 05AB1E, 8 bytes

ZLåÅÏs.V


Try it online! Uses 1-based indexing.

ZLåÅÏs.V  # full program
ÅÏ     # for elements in...
# implicit input...
ÅÏ     # where corresponding element in...
å       # is...
# (implicit) each element in...
L        # [1, 2, 3, ...,
Z         # ..., largest element of...
# implicit input...
L        # ]...
å       # in...
Z         # implicit input...
ÅÏ     # is 1 replace current element in map with...
.V  # result of running...
s    # implicit input...
.V  # as 05AB1E code
# (implicit) exit map
# implicit output

• This is 8 bytes, not 9? And you may want to specify you've used 1-based indexing, since 05AB1E is 0-based usually. Nice answer though, +1 from me. :) Jun 14 at 10:37
• @KevinCruijssen Oops! Jun 14 at 15:52

# Factor + math.unicode, 50 bytes

[ '[ _ ∈ [ call ] [ drop ] if ] with map-index ]


Try it online!

## Explanation:

It's a quotation (anonymous function) that takes a quotation with stack effect ( x -- x ), a sequence of values, and a sequence of 0-indexed indices (in that order) from the data stack as input and leaves a sequence of results on the data stack as output. Assuming [ sq ] { 4 5 } { 0 } is on the data stack when this quotation is called...

• '[ _ ∈ [ call ] [ drop ] if ] Place a quotation on the stack for with to use later. However, ' starts a fried quotation, which says to slot whatever is on top of the data stack into the _. When _ appears on the left side of a quotation like this, it's just a shorthand for currying a quotation.

Stack: [ sq ] { 4 5 } [ { 0 } ∈ [ call ] [ drop ] if ]

• with Partial application on the left. It sticks the [ sq ] into the quotation in such a way that it comes before whatever the following combinator puts on top of the data stack.

Stack: { 4 5 } [ [ sq ] [ { 0 } ∈ [ call ] [ drop ] if ] swapd call ]

• map-index Apply a quotation to each element of a sequence, collecting the results into a sequence of the same size. However, map-index will also place the index of the element being mapped on top of the data stack. Inside the quotation during the first iteration now...

Stack: 4 [ sq ] 0 { 0 } ! element, function, index, indices

• ∈ Shorthand for member? Returns t if the object second from the top is in the sequence on top of the stack.

Stack: 4 [ sq ] t

• [ call ] [ drop ] Push some quotations for if to use later.

Stack: 4 [ sq ] t [ call ] [ drop ]

• if If third from the top is t, call the first quotation, otherwise call the second.

Stack: 16

• Now map-index collects this result into the sequence it's building and proceeds with the next iteration.

Stack: 5 [ sq ] 1 { 0 }

• This time, the index is not found in the indices, and so [ sq ] gets dropped instead of called.

Stack: { 16 5 }

# APL (Dyalog Unicode), 6 bytes

Full program which is just a thin cover for the built-in @ ("At") operator. Uses whichever indexing APL currently uses (can be 0 or 1).

⎕¨@⎕⊢⎕


Try it online!

⊢⎕ on $$\L\$$

@⎕ at indices $$\I\$$

⎕¨ apply $$\f\$$ to each

Without the built-in:

L←⎕
L[I]←⎕¨L[I←⎕]
L


Try it online!

L←⎕ get $$\L\$$

L[] extract the following elements from $$\L\$$:
I←⎕ get $$\I\$$
⎕¨ get $$\f\$$ and apply it to each
L[I]← let those values replaces the values in $$\L\$$ at indices $$\I\$$

L print the updated $$\L\$$

• APL continues to impress me. I don't think I've used the @ operator before. May 6 at 19:47

# R, 38 bytes

function(l,i,f){l[i]=sapply(l[i],f);l}


Try it online!

1-based indices.

If we can assume that f is vectorized (perhaps by use of Vectorize()), then this would be 31 bytes:

function(l,i,f){l[i]=f(l[i]);l}


# J, 13 bytes

1 :'u@{[]}'


Try it online!

An adverb modifying the function, taking the 0-based indexes as left arg and L as the right arg. Called like:

indexes  black box function
v     v
0 1 2 3 (>: f) 7 12 14 6
^
list L to transform


This is just a very thin wrapper over the gerund form of J's Amend adverb, using { to pluck the values we want to transform and then applying our black box function to them @u.

# Husk, 7 bytes

z?⁰IM€N


Try it online!

Husk probably needs a builtin for this and/or for converting a list of indices into a boolean mask.

### Explanation

z?⁰IM€N    Inputs: function, indices, list of values
M€N    Build a list saying for each natural number if it is present in the indices
z          Pair each element of this list to one of the values and
?          if it is truthy
⁰          apply the input function
I        else, apply the identity function (leave the value unchanged)


# Raku, 17 bytes

{@^h[@^i]».=&^f}


Try it online!

0-based indexing. Modifies the input array in-place.

• -1 byte thanks to Unrelated String, by reminding me that infix is not always better.
• -1 byte thanks to xnor, by suggesting take/drop instead of splitAt.
foldl.h
h f l i=take i l++f(l!!i):drop(i+1)l


Try it online!

The relevant function is foldl.h, which takes as input f, l, i. The list of indices i is 0-indexed.

## How?

h f l i=take i l++f(l!!i):drop(i+1)l


The function h applies f to the i-th element of the list l. Since Haskell is very unappreciative of mutable variables, the only way to do it is concatenating the first i elements of l, then f applied to the i-th element, and finally the rest of l.

foldl.h≡\f l i->foldl(h f)l i


This repeats the previous function for all the indices in the input list i.

foldr.adjust
import Data.Sequence


Try it online!

Basically the same solution, but uses the Seq type from Data.Sequence instead of a List. The import is costly, but the h function from the above solution is already implemented as adjust.

• -1 by not defining infix May 5 at 7:15
• @UnrelatedString Well that was unexpected... I guess infix is not always better ^^. Thanks! May 5 at 7:20
• Looks like the more boring take/drop approach is actually 1 shorter: TIO
– xnor
May 5 at 7:26
• This recursive version is also 44, but you might be able to get it shorter using an infix function or something.
– xnor
May 5 at 7:36

# x86-16 machine code, 11 bytes

        I_LOOP:
AD          LODSW                       ; next index into AX
97          XCHG AX, DI                 ; index in DI
8A 01       MOV  AL, BYTE PTR[BX+DI]    ; AL = value of L
FF D5       CALL BP                     ; call BlackBox (tm) function
88 01       MOV  BYTE PTR[BX+DI], AL    ; value of L = AL
E2 F6       LOOP I_LOOP                 ; loop until end of I


L list at [BX], I list at [SI] (zero indexed), I length in CX. BlackBox function at [DS:BP], input value/return in AL.

Example run with DEBUG. The "interesting" parts have been highlighted for those who don't speak DEBUG.

# Lua, 67 bytes

function g(f,l,i)for k,v in pairs(i)do l[v]=f(l[v])end return l end


Try it online!

Uses 1-indexing, i always forget lua uses 1 indexed tables

# Stax, 14 bytes

Yd{diyI^n_aaMm


Run and debug it

The fully manual method, takes args as block arr arr. Requires 0-indexed indices.

the final result is put on the top of the stack.

The single byte builtin for this which takes args arr arr block is &.

# Icon, 43 bytes

procedure a(L,I,f)
L[k:=!I]:=f(L[k])&\z
end


Try it online!

# Ruby, 33 bytes

->g,l,i{i.map{|x|l[x]=g[l[x]]};l}


Try it online!

• You can drop ;l and state that your function modifies the list in-place, as many other answers are doing. May 5 at 20:52
• g[l[x]] really? I was thinking about g(l[x]) or just g l[x] for one less byte.
– iBug
May 8 at 1:48
• @iBug OP's program works with lambdas, which cannot be called like the rest of ruby's methods. With your proposal, ruby would attempt to look up a method named g, of which there is nothing natively defined. Ruby's procs/lambdas must be called with square brackets, or with .call. May 8 at 5:18

# C#, 50 bytes

(f,L,I)=>L.Select((v,i)=>I.Contains(i+1)?f(v):v);


Online demo: https://dotnetfiddle.net/M4YbOx

# Scala 3, 50 bytes

f=>I=>_.zipWithIndex.map((?,i)=>if(I(i))f(?)else?)


Try it in Scastie!

Stupid function parameter names ftw! Indexing starts at 0.

f=>  //The blackbox function
I=>  //The Set of indices
_   //The list of integers
.zipWithIndex //Zip each element with its index
.map((?,i)=>  //Map each element ? and its index i
if(I(i))    //If the Set of indices contains i
f(?)       //apply f to ?
else ?     //Otherwise, just return ?
)


# BQN, 10 bytes

{𝔽⌾(𝕨⊸⊏)𝕩}


Try it online!

To show off structual under ⌾ which is a little bit more powerful than J's &. as I found out yesterday. {…} defines a block where we get access (among other things) to 𝕩 as the right argument, 𝕨 the left, and 𝔽 the function that gets modified. So this calls 𝔽⌾(𝕨⊸⊏) with 𝕩. ⌾ executes the right part, then the left part, and then the inverse of the right part. But unlike &. it also remembers the original array at the inverse step, so it can be used to update the array. So 𝕨⊸⊏ takes the elements of 𝕩 at the indices of 𝕨. On these elements 𝔽 gets called. Then the elements get re-inserted into the original arrays at the indices of 𝕨.

# Java, 42 38 bytes

(a,i,f)->{for(int j:i)a[j]=f.f(a[j]);}


Saved 4 bytes thanks to Olivier Grégoire.

Try it online!

• I'm quite sure you can define your own function interface to reduce apply to only one letter. May 5 at 15:45
• @OlivierGrégoire Thanks for the tip. May 5 at 16:00

# C (clang), 54 $$\\cdots\$$ 52 43 bytes

Saved 9 bytes thanks to att!!!

f(g(),*L,*I,n){for(;n--;)L[*I++]=g(L[*I]);}


Try it online!

Inputs a pointer to a function $$\g\$$ (inputting an int parameter and returning an int), a pointer to an array of positive integers $$\L\$$, a pointer to an array of $$\0\$$-base indices $$\I\$$, and $$\I\$$'s length $$\n\$$ (since pointers in C carry no length info).
Updates $$\L\$$ in place.

### Explanation

f(g(),*L,*I,n)                       // golfed function signature for:
// int f(
//       int (*g)(int),
//       int *L,
//       int *I,
//       int n
//      )
{                                    //
for(;n--;)                          // loop over I
L[*I  ]=                  // assign L at current index in I
g(     );         // to g's return value of
L[*I]           // L at current index in I
++                    // bump I to next index

• f(g(),*L,*I,n){for(;n--;)L[*I++]=g(L[*I]);} for 43 bytes
– att
May 6 at 19:08
• @att Nice one - thanks! :D May 6 at 19:12

# Julia, 19 bytes

f*L*i=L[i]=f.(L[i])


with 1-based indexing

changes L itself as the output

Try it online!

# MMIX, 44 bytes (11 instrs)

Takes f, L, I, len(i); both L and I are lists of uint64_t. f is also necessarily MMIXware argument passing.

(jxd -T)

00000000: fe040004 3b030303 27030308 8e050203  “¥¡¥;¤¤¤'¤¤®⁾¦£¤
00000020: 5b03fffa f6040004 f8000000           [¤”«ẇ¥¡¥ẏ¡¡¡


Disassembly/explanation:

foo GET    $4,rJ SLU$3,$3,3 0H SUBU$3,$3,8 // loop: leni-- LDOU$5,$2,$3     // j = I[leni]
SLU    $5,$5,3
LDOU   $7,$1,$5 // a = L[j] PUSHGO$6,$0,0 // b = f(a) STOU$6,$1,$5     // L[j] = b
PBNZ   $3,0B // iflikely(leni) goto loop PUT rJ,$4
1H  POP    0,0          // return


# Kotlin, 48 bytes

{f,L,I->L.mapIndexed{i,v->if(i in I)f(v)else v}}


Try it online!

Very straight-forward algorithm. Uses the default rule for submitting lambdas.

# Wolfram Language (Mathematica), 5 bytes

MapAt


Try it online!

Takes input in a slightly annoying format: to apply f to {a,b,c,d,e} at positions {1,3,5} and get {f[a],b,f[c],d,f[e]}, we write

MapAt[f, {a,b,c,d,e}, {{1},{3},{5}}]


Some other varyingly built-in solutions:

• 18 bytes: MapAt[#,List/@#2]&. Takes input [f,I][L]. The {{1},{3},{5}} syntax bothers me a little, so this lets I be an actual list.
• 20 19 bytes: Map@#~SubsetMap~#2&. Takes input [f,I][L]. SubsetMap differs from MapAt in that it applies the function to all the elements at some indices at the same time.
• 27 bytes: (s=#3;s[[#]]=#2/@s[[#]];s)&. Takes input [I,f,L]. Here, we assign the input to a variable, and manually change the values at positions indexed by I.
• Inputting as {{1},{3},{5}} is fine, if you want to claim the 5 byter :) May 6 at 21:27
• I'll take it! :) May 6 at 21:30
• The 20-byter can be written infix as Map@#~SubsetMap~#2&.
– att
May 7 at 3:46

# Attache, 2 bytes

On


Try it online!

There's a Builtin for That™.

Another builtin solution, 8 bytes: Over@->.

## Without builtins, 22 bytes

-2 bytes after reading other answers, since this modifies the variable in place. Prepend ;z before the last } to have it also return the value.

${{Set[z,_,y!z@_]}=>x}  Try it online! 23 bytes: ${z&Set&>Tr![x,z[x]|y]}

23 bytes: ${&@(z&Set)![x,z[x]|y]} 31 bytes: ${{[_,y@_][_2in x]}&>@V#Iota!z}

32 bytes: ${{If[_2in x,y@_,_]}&>@V#Iota!z} 33 bytes: ${{[_,_|y][_2in x]}&>Enumerate@z}

33 bytes: ${{[Id,y][_2]!z@_}#x&Has=>Iota@z} 34 bytes: ${{z@_|If[_2,y,Id]}#x&Has=>Iota@z}

34 bytes: ${{If[x&Has!_2,y@_,_]}&>@V#Iota!z} 34 bytes: ${{[Id,y][x&Has!_2]!_}&>@V#Iota!z}

# Zsh, 36 bytes

for x;grep -xq $[++i] f&&F$x||<<<$x  Try it online! Expects a function predefined as F, the operand array as command-line arguments, and the indeces from the file f, each on one line. for x;: for each $x in the command-line arguments:

• $[++i]: increment $i (which starts at 0 implicitly)
• grep -xq f: check if $i is present in the file f • -q: return success/failure only, don't print matching lines • -x: require the whole line to match $i. Otherwise 14 would erroneously match 4
• &&: if that succeeds:
• F $x: call F with the argument $x
• ||: else:
• <<<$x: just print $x unaltered

# Racket, 97 bytes

(define(a L I f[n 1])(if(null? L)'()(cons(if(member n I)(f(car L))(car L))(a(cdr L)I f(+ 1 n)))))
`

Try it online!