# Distance to closest subsequent value

Inspired by this SO post.

Given a vector (first parameter), e.g.:

char = ["A", "B", "C", "A", "A"]


For each element of the vector, find the distance to the closest subsequent specified value (second parameter). When the element is identical to the specified value, return 0.

f(char, "A") -> [0 2 1 0 0]


Explanation

f(char, "A") returns [0 2 1 0 0] because f returns the distance to the closest following value that equals "A". The first value of char is "A", so as the element is equal to the desired value, return 0. For the second element, "B", the closest "A" is two positions away from it (position 4 - position 2 = 2). For the third element "C", the closest subsequent "A" is 1 position away from it.

When there are no subsequent values that match the specified value, return nothing. When the specified value is not part of the vector, the function can either return an empty vector or throw an error.

The function should work for string vectors or integer vectors.

Tests

char = ["A", "B", "C", "A", "A"]
f(char, "B") -> [1 0]
f(char, "C") -> [2 1 0]
f(char, "D") -> []

int = [1, 1, 0, 5, 2, 0, 0, 2]
f(int, 0) -> [2 1 0 2 1 0 0]
f(int, 1) -> [0 0]
f(int, 2) -> [4 3 2 1 0 2 1 0]


This is so the shortest code in each language wins.

• How is the closeness between strings determined? Is AA closer to AB or BA? Are we supposed to support strings longer than 1 character? Commented Feb 8, 2022 at 9:40
• It should be an exact match. So, f(char, "AA") will return []. Strings can be longer than one character. Is that clear?
– Maël
Commented Feb 8, 2022 at 9:54
• @WheatWizard - My reading is that we need to find the distance to the closest (=least number of elements away) identical element, so we only need to check identity between elements. Commented Feb 8, 2022 at 9:54
• The function should work for any vector, whether it contains strings or integers precludes typed languages like C, why not make it either?. Commented Feb 8, 2022 at 17:07
• Edited. It was a bit unnecessarily restrictive I agree.
– Maël
Commented Feb 8, 2022 at 17:46

x#(a:b)|x==a=0:x#b|y:q<-x#b=y+1:y:q
_#_=[]


Try it online!

For every element, if it equals the search value then it's 0, if it doesn't then it is 1 greater than the next value.

# R, 48 bytes

-2 bytes thanks to Giuseppe. -1 byte thanks to Dominic van Essen.

\(v,x)sequence(d<-diff(c(0,which(v==x))),d-1,-1)


output

f(int, 0)
# [1] 2 1 0 2 1 0 0
f(int, 1)
# [1] 0 0
f(int, 2)
# [1] 4 3 2 1 0 2 1 0
f(int, 3)
# integer(0)

f(char, "A")
# [1] 0 2 1 0 0
f(char, "B")
# [1] 1 0
f(char, "C")
# [1] 2 1 0
f(char, "D")
# integer(0)


Works for R >= 4.1.0.

• You probably want to consider removing the space after the function definition, too... Commented Feb 8, 2022 at 13:32
• Ahah, right... thanks
– Maël
Commented Feb 8, 2022 at 13:35

# R, 56 51 bytes

Edit: -5 bytes thanks to Giuseppe

f=function(l,x)if(y<-match(x,l,0))c(y-1,f(l[-1],x))


Try it online!

Works for any version of R.
For R version ≥4.1.0, change "function" to "\" for 44 bytes.

• The sum() is not necessary. Commented Feb 8, 2022 at 14:10
• @Giuseppe - Gah! Thanks! I'm terrible at removing all the fossils of previous code-attempts... Commented Feb 8, 2022 at 14:38

# Python, 38 bytes

def f(a,x):f(a[1:print(a.index(x))],x)

Attempt This Online!

Finishes with an exception

-5 bytes thanks to AnttiP

-1 thanks to dingledooper

## Whython, 40 bytes

def f(a,x):f(a[1:print(a.index(x))],x)?0

Attempt This Online!

No error

• -5 bytes: Attempt This Online! Commented Feb 9, 2022 at 8:36
• You can actually place the print statement inside the slice, like so: a[1:print(a.index(x))]. Commented Feb 11, 2022 at 21:24

# Vyxal, 11 bytes

ṘKRṘ=vTvßhf


Try it Online!

ṘKRṘ        # Get suffixes
=       # Find those that are equal
vT     # Get truthy indices of each
vßh  # For each, if it is truthy, get the first
f # Flatten (remove empty values)


Or if we can return zeroes if the required value is not at the end:

# Vyxal, 8 bytes

ṘKRṘ=ƛTh


Try it Online!

ṘKRṘ     # Over suffixes...
=    # Check if each value is equal to the second input
ƛ   # Map...
Th # Find the first index where it is equal

• This produces too long results of the second input is not at the last index.
– ovs
Commented Feb 8, 2022 at 10:49

# tinylisp, 73 71 bytes

(load library
(d F(q((L V)(filter inc(i L(c(first-index L V)(F(t L)V))(


Try it online!

Ports, e.g., Dominic van Essen's answer.

Uses this tip to filter out nil results from first-index.

# tinylisp, 79 bytes

(d I(q((L V)(i L(c(i(e(h L)V)0(a(h(I(t L)V))1))(i(a(h(I(t L)V))1)(I(t L)V)()))(


Try it online!

Without library it's a little longer, but the recursion was fun to figure out (and likely still golfable somehow).

# JavaScript (Node.js), 49 bytes

c=>g=z=>~(r=z.indexOf(c))?[r,...g(z.slice(1))]:[]


Try it online!

Byte shorter than Arnauld and tsh

# Python 3, 51 49 bytes

1 byte from AnttiP

f=lambda a,k:a*(k in a)and[a.index(k)]+f(a[1:],k)


Try it online!

• You can save a byte in the python answer if you just use list addition: Try it online! Commented Feb 9, 2022 at 8:28

# Ruby 2.7.4, 56 54 bytes

->(a,l){a.filter_map.with_index{|_,i|a[i..].index(l)}}


Filter maps over the array and finds the index of the target offset from the current index.

Try it on Replit!

Excited to have gotten my first Golf!

• Welcome to Code Golf! Nice answer! You might also want to check out tips for golfing in ruby Commented Feb 11, 2022 at 21:14
• Welcome to Code Golf, and nice first answer! You're allowed to submit anonymous functions here, so you can discout the f= from your score, and you might want to add a TIO link so others can test your code. Commented Feb 11, 2022 at 21:29
• Thank you for the tips both of you! Added a Replit link because TIO didn't like the Ruby 2.7 endless range syntax.
– Jack
Commented Feb 12, 2022 at 23:47

# Python 3.8 (pre-release), 62 bytes

lambda n,k:[n[i:].index(k)for i in range(len(n))if k in n[i:]]


Try it online!

Pretty straightforward: for each index i, find the index of the list starting at index i of k (second argument) and add it to the output if k is in fact in the list starting at index i.

# Factor, 56 bytes

[ indices -1 prefix differences [ 0 (a,b] ] map concat ]


Try it online!

## Explanation

Takes input as element sequence.

                 ! 0 { 1 1 0 5 2 0 0 2 }
indices          ! V{ 2 5 6 }
-1 prefix        ! V{ -1 2 5 6 }
differences      ! { 3 3 1 }
[ 0 (a,b] ] map  ! { { 2 1 0 } { 2 1 0 } { 0 } }
concat           ! { 2 1 0 2 1 0 0 }


# Jelly, 5 bytes

iÐƤ¹Ƈ


Try it online!

Returns values 1-indexed. Tack on a ’ for 0-indexed values. Port of my Vyxal answer.

 ÐƤ    Map over the suffixes...
i      Find the first index of the other value in each
¹Ƈ  Filter out zeroes

• =TḢɗ -> i...? Commented Feb 8, 2022 at 19:29
• @UnrelatedString Did not know that existed, thanks! Commented Feb 8, 2022 at 19:39

# BQN, 18 bytesSBCS

{∾⌽∘↕¨+⁼1+/𝕨⊸≡¨𝕩}


Run online!

𝕨⊸≡¨𝕩 binary mask with 1's where the left argument appears in the right.
1+/ 1-based indices.
+⁼ differences between adjacent indices with the first value staying.
⌽∘↕¨ reversed range for each difference.
∾ join into a single list.

• Doesn't ¯1↓⊐˜¨⟜↓ work?
Commented Feb 8, 2022 at 10:39
• @Adám You have to truncate the result after the left arguments last occurence and having to handle strings longer than 1 character would break this (I think?). I did try using ↓, but my best attempt was {>⌾(⌽¬)∘×⊸/>⊐⟜(<𝕨)¨↓𝕩} (I'm sure it can be improved)
– ovs
Commented Feb 8, 2022 at 10:44

# APL(Dyalog Unicode), 32 bytes SBCS

{∊(⍳≢⍵)(×∘≢⍴|)⍤(-⊢⍤⌿⍨0≥-)¨⊂⍸⍺=⍵}


Try it on APLgolf!

or

# APL(Dyalog Unicode), 32 bytes SBCS

(∊⍳∘≢⍤⊢(×∘≢⍴|)⍤(-⊢⍤⌿⍨0≥-)¨⊂∘⍸⍤=)


Try it on APLgolf!

Equivalent submissions, first one is a dfn and second one is tacit.

# JavaScript (ES10), 50 bytes

Expects (list)(value).

a=>v=>a.flatMap((_,i)=>~(j=a.indexOf(v,i))?j-i:[])


Try it online!

# 05AB1E, 8 bytes

.sRIδk®K


Explanation:

.s        # Get the suffixes of the first (implicit) input-list
R       # Reverse it
δ     # Map over each inner suffix:
I k    #  Get the (first) 0-based index of the second input
#  (or -1 if it isn't present)
®K  # Remove all -1s
# (after which the result is output implicitly)


# Wolfram Language (Mathematica), 47 bytes

Min[p=p-1/.-1->{}]&~Array~Max[0,p=Position@##]&


Try it online!

Input [vector, value].

# JavaScript (Node.js), 52 bytes

a=>v=>a.map((u,i)=>a.indexOf(v,i)-i).filter(x=>x>=0)


Try it online!

• .filter(x=>~x) for 48? Commented Feb 8, 2022 at 19:45
• @Arnauld, yes, The answer was incorrect before, it was only possible to have -1 in the array, now it has been fixed though Commented Feb 9, 2022 at 15:50

# Charcoal, 14 bytes

ＩΦＥθ⌕✂θκＬθ¹η⊕ι


Try it online! Link is to verbose version of code. Explanation:

   θ            Input array
Ｅ             Map over elements
⌕           Find index of
η    Value to match in
θ         Input array
✂          Sliced from
κ        Current index to
θ      Input array
Ｌ       Length
¹     Step literal integer 1
Φ              Filtered where
ι  Current value
⊕   Is not -1
Ｉ               Cast to string
Implicitly print


Slicing arrays is very awkward in Charcoal but it's the same length as filtering (ＩΦＥθ⌕Φθ¬‹μκη⊕ι).

# Burlesque, 13 bytes

iSjqFi_+m[:+.


Try it online!

Takes input as value as a list and the list of search, i.e. {1} {1 2 3}. The filter works because the +. increment operation works as: -1+. -> 0, 0+. -> 1, 1+. -> 2... and 0 is falsy.

iS  # Generate all tails
j   # Swap stack
qFi # Quoted Find index (returns -1 on fail)
_+  # Append to value (making {value Fi})
m[  # Map block as function
:+. # Filter for not -1


# Python 3, 58 bytes

lambda a,k:[[a.index(k),a.pop(0)][0]for i in[*a]if k in a]


Try it online!

# Julia 1.0, 48 bytes

x\y=[(:).(diff([0;findall(x.==y)]).-1,-1,0)...;]


Try it online!

# C (gcc), 81 bytes

j;i;f(a,n,h)int*a;{for(j=i=0;i<n&j<n;a[i++]=j-i)for(j=i;j<n&&a[j]-h;++j);i-=j/n;}


Try it online!

Inputs a pointer to an array of integers, its length (because pointers in C carry no length info), and a target value.
Returns the length of the the array of distances to the closest subsequent target and that array is returned in the input array.

# Pari/GP, 51 bytes

f(a,b)=[l[1]-i|i<-[1..#a],l=[j|j<-[i..#a],a[j]==b]]


Try it online!

# Pari/GP, 53 bytes

f(a,b)=s=t=0;r=Vecrev;r([s=!d*s++|c<-r(a),t+=d=c==b])
`

Try it online!