Write a function that takes in a string and for each character, returns the distance to the nearest vowel in the string. If the character is a vowel itself, return 0.

Vowels are : aeiouAEIOU

For the purposes of this challenge, y is not a vowel.

The input will be a string consisting of uppercase and lowercase letters.

Edge cases :

  • You will be tested for empty strings as well, so '' is a valid input, which should return []

  • The input string will contain at least one vowel (unless it is the empty string)

  • Obviously in case someone missed it uppercase and lowercase letters both exist

  • It is also possible you end up getting nothing but vowels in a string, the answer in that case obviously would be 0 across the board

Examples :

distanceToNearestVowel("aaaaa") ➞ [0, 0, 0, 0, 0]

distanceToNearestVowel("abcdabcd") ➞ [0, 1, 2, 1, 0, 1, 2, 3]

distanceToNearestVowel("shopper") ➞ [2, 1, 0, 1, 1, 0, 1]

distanceToNearestVowel("")        ➞ []

distanceToNearestVowel("AaAaEeIeOeAU") ➞ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

distanceToNearestVowel("bcdfghjklmno") ➞ [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] ----> added thnx to @Shaggy

Input : String

Output : Array or string (or equivalent in your language of choice)

This is , so the shortest answer in each language wins.

I will probably not mark any answer as accepted (since different languages different standards)

If you can and have some time kindly do explain your answers (this is mostly for me so I can understand how they work; I like learning. Obviously not compulsory.)

  • 3
    \$\begingroup\$ This looks like a reasonably well-specified challenge, but for future reference, it's recommended to put challenges in the sandbox to get feedback before posting them. \$\endgroup\$ Commented Aug 30, 2021 at 15:49
  • 1
    \$\begingroup\$ hey anyone know if we can answer our own question? \$\endgroup\$ Commented Aug 30, 2021 at 16:47
  • 1
    \$\begingroup\$ @EternalStudent to answer your own question wait at least a day first (I think you are going to post the answer in JS, it is very less likely you may post an answer after a day, people will ninja you soon) \$\endgroup\$
    – Wasif
    Commented Aug 30, 2021 at 16:49
  • 1
    \$\begingroup\$ @EternalStudent yes answering you own question is encouraged on stack exchange. On this site it is recommended to wait a while if your own answer has a really good score, to avoid discouraging others. \$\endgroup\$ Commented Aug 30, 2021 at 16:51
  • 2
    \$\begingroup\$ Would a value like false/null/undefined be a valid output for an empty string input? \$\endgroup\$
    – Kaddath
    Commented Aug 31, 2021 at 8:22

32 Answers 32


Jelly, 10 bytes


A monadic Link that accepts a list of characters and yields a list of non-negative integers.

Try it online!


e€ØcTạⱮJṂ€ - Link: list of characters, S  e.g. "shopper"
  Øc       - vowels                            "aeiouAEIOU"
 €         - for each (c in S):
e          -   (c) exists in (vowels)?         [0,0,1,0,0,1,0]
    T      - truthy indices                    [3,6]
       J   - range of length (S)               [1,2,3,4,5,6,7]
      Ɱ    - map with:
     ạ     -   absolute differences            [[2,5],[1,4],[0,3],[1,2],[2,1],[3,0],[4,1]]
        Ṃ€ - minimum of each                   [2,1,0,1,1,0,1]

APL(Dyalog Unicode), 23 bytes SBCS


Try it on APLgolf!

Needs version 18 for the new Case Convert system function.

⎕C convert the argument to lower. According to the documentation this folds the case for case-less comparisons but it is actually implemented as converting to lower case, at least for the latin alphabet.
'aeiou'∊ for each character, is it a vowel?
get all indices of 1's (vowels)

⍳∘⍴ all indices from 1 to the length of the string
∘.- table of differences between each index and each index of a vowel
| the absolute value of each difference
⌊/ for each index in the string, get the minimum value


Python 2, 88 85 bytes

-3 bytes thanks to dingledooper

lambda s,E=enumerate:[min(abs(j-i)for j,y in E(s)if y in'aeiouAEIOU')for i,_ in E(s)]

Try it online!

  • 2
    \$\begingroup\$ It looks to save you 3 bytes to use a lambda instead, with enumerate to loop. \$\endgroup\$ Commented Aug 31, 2021 at 6:23
  • 1
    \$\begingroup\$ @dingledooper thanks a lot! I tried using enumerate earlier with a normal function in Python 3 and got something longer, so I was convinced it wouldn't be of any help here \$\endgroup\$
    – ovs
    Commented Aug 31, 2021 at 8:18

Haskell, 70 bytes

(\z->[minimum[abs$i-j|(j,c)<-z,elem c"aeiouAEIOU"]|(i,_)<-z]).zip[0..]

Try it online!


JavaScript (ES6),  83  69 bytes

Expects an array of ASCII codes.


Try it online!


a =>                      // a[] = input array
a.map((_, x) =>           // for each entry at position x in a[]:
  a.map(m =               //   initialize m to a non-numeric value
    c =>                  //   for each ASCII code c in a[]:
    m =                   //     update m:
      ( v =               //       set v to abs(x)
        x-- < 0 ? ~x      //       and decrement x afterwards
                : -~x     //
      ) > m |             //       if v is greater than m
      ~2130466 >> c & 1 ? //       or c is the code of a consonant:
        m                 //         leave m unchanged
      :                   //       else:
        v                 //         update it to v
  ) | m                   //   end of inner map(); yield m
)                         // end of outer map()
  • 1
    \$\begingroup\$ How does the magic constant 2130466 work? \$\endgroup\$
    – emanresu A
    Commented Aug 31, 2021 at 8:47
  • 2
    \$\begingroup\$ @emanresuA I described the method in this answer (except it was left-shifted by 5 bits in order to get 0 or 32 instead of 0 or 1 here). \$\endgroup\$
    – Arnauld
    Commented Aug 31, 2021 at 8:51

Haskell, 72 bytes, \$O(n^2)\$

f x|q<-zip[0..]x=[minimum[abs$i-j|(j,v)<-q,elem v"aeiouAEIOU"]|(i,_)<-q]

Try it online!

I realized I I was still holding onto an efficiency mindset when I was golfing this earlier, which isn't needed for codegolf. This goes through every letter in the input and checks the distance to every vowel taking the minimum.

Haskell, 95, 92 bytes, \$O(n)\$

g u=u(%)=<<length
zipWith min.g scanr<*>tail.g(scanl.flip)

Try it online!

We create a scanning function (%). This takes a number and a character. If the character is a vowel it gives 0 otherwise it gives one more than the provided number.

We scan the input from right to left starting with the total length of the list


We chop off the extra number at the start. Then we do the same scan in the other direction


We don't bother chopping the extra here, because next we zip the two together taking the minimum entry in each list


And that is our result.

This answer happens to implement the original spec of the challenge giving the length of the list when there are no vowels, whereas the first has an error on this case.


R, 82 bytes

-1 byte thanks to @Dominic van Essen.


Try it online!

(or R>=4.1, 68 bytes replacing both function appearances with \)

Previous solution (with explanation):

R, 83 bytes


Try it online!

function(x){      # a function taking string x
a=seq(l=nchar(x)) # make a sequence 1..length(x) (empty if x empty)
b=el(             # take first (and only) element of list with
     gregexpr(    # positions
      "[aeiou]",  # of vowels
      x,          # in x
      T))         # with ignored case
c=outer(a,b,`-`)  # matrix of position differences 
                  # with length(x) rows and (# vowels in x) columns
d=abs(c)          # absolute value
apply(d,1,min)    # row-wise minimum
  • 1
    \$\begingroup\$ Nice! -1 byte by returning a list instead of a vector. \$\endgroup\$ Commented Aug 30, 2021 at 21:19

jq, 73 69 62 bytes

-7 bytes thanks to Michael Chatiskatzi!


Try it jqplay! fabs, like many of the math builtins, doesn't seem to work on TIO.

  • \$\begingroup\$ 62 bytes \$\endgroup\$ Commented Sep 7, 2021 at 12:23
  • \$\begingroup\$ @MichaelChatiskatzi thanks a lot! A filter with as returns its input unchanged? I always was it annoyed that it doesn't return the new value of the variable, but this might actually be better :) \$\endgroup\$
    – ovs
    Commented Sep 7, 2021 at 13:03

Japt v2.0a0, 12 bytes

¬£ð\v maY rm

Try it or run all test cases

¬£ð\v maY rmUl     :Implicit input of string U
¬                  :Split
 £                 :Map 0-based indices Y
  ð                :  0-based indices in U of
   \v              :    RegEx /aeiou/i
      m            :  Map
       aY          :    Absolute different with Y
          r        :  Reduce by
           m       :    Minimum
  • \$\begingroup\$ Exactly what I had, except for Íg instead of rm \$\endgroup\$ Commented May 6, 2023 at 17:00

J, 36 34 bytes


Try it online!

-2 thanks to FrownyFrog

Solved independently, but appears to be almost identical to ovs's APL approach.

  • 2
    \$\begingroup\$ 34 \$\endgroup\$
    – FrownyFrog
    Commented Aug 30, 2021 at 22:33
  • 1
    \$\begingroup\$ Thanks @FrownyFrog! Good to see you around. \$\endgroup\$
    – Jonah
    Commented Aug 30, 2021 at 23:58

JavaScript, 75 bytes


Try it online!

Input an array of characters, output an array of numbers. For input which is both non-empty and contains no vowels, it returns Infinity.

It would be 74 bytes if we allow return false in place of 0:


A typical solution runs in \$O\left(n\right)\$. Looks like most other answers are \$O\left(n^2\right)\$.


Wolfram Language (Mathematica), 72 bytes


Try it online!

Input a character list.


JavaScript, 73 bytes

Takes input as an array of characters.


Try it online!

This started off at around 100 bytes but I tapped away at it through most of an insomniac night, determined to beat Arnauld's 83 only to come back this morning to discover that not only had he blown me out of the water by knocking 14 bytes off his score but tsh had also sniped me by a byte. Borrowing Arnauld's absolute value trick, though, allowed me to save 3 bytes putting me in second place (for now) so I'll take it. Still think there's a byte or 2 more to be shaved off this but that'll need to wait until caffeine kicks in.

  • 1
    \$\begingroup\$ I feel your pain. tsh and Arnauld are very good at this. \$\endgroup\$
    – emanresu A
    Commented Aug 31, 2021 at 20:04
  • \$\begingroup\$ Hey! I have my moments, too, @emanresuA! :p \$\endgroup\$
    – Shaggy
    Commented Sep 1, 2021 at 9:09
  • \$\begingroup\$ So do I \$\endgroup\$
    – emanresu A
    Commented Sep 1, 2021 at 9:11

Retina, 63 bytes


Try it online! Link includes test cases. Explanation:


Looping over each letter, look for nearby vowels.


Loop over each result separately.


Take the minimum. (I feel there should be a shorter way to do this, but I can't think what is might be.)


PHP < 7.1.0 -F , 125 bytes


Try it online! (wrong PHP version, works with some test cases)

test the last case (or others) with the right version of PHP

This is the first shot I gave it to it, without looking at other answers, pretty sure it can be golfed more using subte tricks.

Straightforward code, only for PHP < 7.1.0 because for newer versions, negative index is supported and accesses chars from the end of the string

displays NULL or empty string for an empty input, depending on the site. It would cost 5 bytes for initialization of $r to an empty array to be sure to have an array as output.


JavaScript, 95 85 bytes


Edits :

@Neil Thanks for the 10 bytes

  • since I've already spread the array, I can just call it using map's third param instead of spreading again
  • Instead of Math.abx() do C>B?C-B:B-C
  • change length a.length to 1/0

Any suggestion on how to improve would be appreciated

  • 1
    \$\begingroup\$ The temporary array you created for the first map is passed as the third parameter to the arrow function; I think you can use this to avoid spreading the string to an array again. It might be shorter to use C>B?C-B:B-C instead of Math.abs but I haven't counted the bytes. You can probably use 1/0 instead of a.length but I haven't tried this. \$\endgroup\$
    – Neil
    Commented Sep 1, 2021 at 23:35
  • \$\begingroup\$ @Neil : alright : so first obviously works (saved 3 bytes). 2nd knocked off 2 bytes. 3rd knocked off (5 bytes). Thanks a bunch \$\endgroup\$ Commented Sep 2, 2021 at 2:58

Vyxal, 7 bytes


Try it Online!

-4 bytes thanks to Lyxal.

 ƛ      # For each
ẏ       # number from 0 to len(input)
    T   # Indices of
   A    # vowels
  ?     # In the input
     ε  # Difference between each index and the given number
      g # Find the minimum

Charcoal, 20 bytes


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

  θ                     Input string
 E                      Map over characters
         θ              Input string
        L               Length
       Φ                Filter over implicit range
                 §θλ    Inner character
                ↧       Lowercase
          №             Is contained in
           aeiou        Lowercase vowels
     ⁻                  Vectorised subtract
      κ                 Current index
    ↔                   Vectorised absolute value
   ⌊                    Minimum
I                       Cast to string
                        Implicitly print

Python 2, 112 bytes

s=input();n=0;exec"print min(abs(y-n)for x in'aeiouAEIOU'if x in s for y,z in enumerate(s)if z==x);n+=1;"*len(s)

Try it online!

Python 2, 115 bytes

def f(s,n=0):print min(abs(y-n)for x in"aeiouAEIOU"if x in s for y,z in enumerate(s)if z==x);n+1<len(s)and f(s,n+1)

Try it online!


# Relavant function
# Recursively check each indices in string
# s is the input string
# idx is the current index 

def f(s, idx=0):

    # The algorithm is
    # We first list the vowels
    # Take their all indices in string
    # Take the absolute difference of the current position with the vowel indices
    # Take the minimum
    # Print

    print min(
              abs(index - idx) 
              for vowel in "aeiouAEIOU" 
              if vowel in s for index, char in enumerate(s) 
              if char == vowel

    # Then check if current index+1 is less than the string length (basically check if we are out of the string)
    # If then we make a recursive call to go to next index
    # If not we short circuit to break the boolean chain and break out of the function

    idx + 1 < len(s) and f(s, idx + 1)

Try it online!

  • 1
    \$\begingroup\$ I don't understand why you need the if x in s condition. If the voyel isn't in the string, the condition if z==x will be false anyway \$\endgroup\$
    – Jakque
    Commented Aug 30, 2021 at 22:13

Perl 5, 89 bytes

sub{$n=1e9;$n=$_?$n:0,$_=$_<$n?$_:$n++for reverse@r=map$n=/[aeiou]/i?0:$n+1,pop=~/./g;@r}

Try it online!


Ruby, 69 bytes


Try it online!

Break it down bro


Initialize with the worst case (will never happen)


For every character of the input string


The value is the minimum between the position of the next vowel in the string (if any) and the previous value incremented by one.


Cut the first character of the string, output the current value.


Python3, 198 bytes


def f(s):
 for i in range(R+2):l.append(L:=0if s[i]in v else L+1);r.append(R:=0if s[~i]in v else R+1)
 return[min(l[x],r[~x])for x in range(len(s))]

removed 42 bytes by removing whitespace (thank you Aaron Miller)
removed 77 bytes shortened variable names(thank you Browncat Programs)
removed 43 bytes by implementing Aaron Miller's solution(thank you Aaron Miller)


def dTNV(s):
 for i in range(len(s)):
  distl=0 if s[i] in 'aeiouAEIOU' else distl+1
  distr=0 if s[-(i+1)] in 'aeiouAEIOU' else distr+1
 return [min(left_min[i],right_min[-(i+1)]) for i in range(len(s))]
  • \$\begingroup\$ Welcome to Code Golf! Make sure to read our tips for golfing in Python to see if there's any suggestions for shortening your code. \$\endgroup\$ Commented Sep 2, 2021 at 16:43
  • \$\begingroup\$ Additionally, we require that answers to code-golf questions make an effort to shorten code. For example, you could remove some whitespace in your indentations, and shorten your variable names. Other than that, this looks like a pretty good answer! \$\endgroup\$ Commented Sep 2, 2021 at 16:48
  • \$\begingroup\$ Variable names like left_min and distl can be shortened to save a lot of bytes \$\endgroup\$ Commented Sep 2, 2021 at 17:25
  • \$\begingroup\$ I shortened a few more things, one-lined some stuff, and did a couple other shenanigans with the walrus operator to get 198 bytes. However, I'm by no means an expert when it comes to golfing Python, so I'm sure somebody else could golf it further. \$\endgroup\$ Commented Sep 2, 2021 at 17:50

Python 3, 174 bytes

def f(s):
	for c,l in enumerate(s):
		while 1:
			if i in range(len(s))and s[i]in'aeiouAEIOU':
	return o

Try it online!

Python 3, 82 bytes

lambda s:[min(abs(s.index(v)-s.index(l))for v in s if v in'aeiouAEIOU')for l in s]

Try it online!

As xnor pointed out, this doesn't work when a vowel appears multiple times in the string. The version above is longer but works when a vowel appears multiple times in the string.

  • 2
    \$\begingroup\$ This doesn't work in general when a character appears multiple times in a string, since .index will only look at the leftmost one, for example for aab. \$\endgroup\$
    – xnor
    Commented Sep 2, 2021 at 22:52
  • \$\begingroup\$ It's fine to include non-working versions of an answer with your working version, but your answer should really put the working version up towards the front, since it is the only valid one. I also suggest you checkout our tips for golfing in Python since you should be able to find some stuff there to improve this a bit. Welcome to the site! \$\endgroup\$
    – Wheat Wizard
    Commented Sep 3, 2021 at 10:50

C++20, 145 141 bytes (+17 bytes with a necessary #include +3 bytes for the general case with int instead of char)

One can use the function (in strict C++ language, it is a function template that can be turned into a function by substituting auto s by std::string s adding another 7 bytes)

auto f(auto s){int c=63,p=0;auto r=s;for(int i:s){for(int x:"AOEUI")c=i-x&~32?c:0;r[p++]=c++;}for(;--p>=0;)r[p]=r[p]<=c++?c=r[p]:c;return r;}

together with std::vector<int> or std::string, which requires the corresponding header to be included (#include<string> or #include<vector> = 16 bytes code + 1 byte line break).

auto f(auto s){
        auto r=s; // r: output (same type and length as s)
        int c=63,p=0; //c: distance counter, p: position in r
        //iterate forwards counting distance from previous vowel (or c+distance from beginning if vowel not yet found) and store it in r
        for(int i:s) {
                for(int x:"AOEUI") {
                        if(!((i-x)&(~32))) c=0; //set c to zero if c is a vowel (assuming ASCII)
                        //i-x == [ 0:upper case, 32:lower case]
                        //(i-x)&(~32) == [ false:i==x ignoring case, true:else ]
        //iterate backwards counting distance and store lower value from both iterations in r
        for(--p;p>=0;--p) {
                if(r[p]<=c) {
                } else {
        return r;

char and int case

In the char case we assume that the input is not longer than 63 bytes. Then the initial value c=63 will not cut off the distance even in cases where the vowel is at the end. It is also small enough not to lead to integer wrap-around, when the type of the elements of the data is signed char (-128..127).

If we want to have the general case for integers, we need to initialize c with a larger value. In that case we substitute

int c=63,p=0;


int c=-1/4u,p=0;

adding 3 more bytes. The signed number -1 corresponds to the largest unsigned integer. Dividing it by unsigned four (4u) converts the -1 to unsigned integer and reduces the value to the middle of the positive signed-integer range.

To cover both cases (char up to 63 bytes and longer int sequences) one can use

int c=size(s),p=0;

which would add 5 bytes compared to the char case.

Usage example:


auto f(auto s){int c=63,p=0;auto r=s;for(int i:s){for(int x:"AOEUI")c=i-x&~32?c:0;r[p++]=c++;}for(;--p>=0;)r[p]=r[p]<=c++?c=r[p]:c;return r;}

int main() {
        std::string result_str=f(std::string("abcdAbcd"));
        std::vector<int> result_vec=f(std::vector<int>({'a','b','c','d','A','b','c','d'}));

        std::cout << "std::string: ";
        for(int i:result_str) std::cout << i << " ";
        std::cout << std::endl;
        std::cout << "std::vector<int>: ";
        for(int i:result_vec) std::cout << i << " ";
        std::cout << std::endl;
        return 0;
  • \$\begingroup\$ Welcome to Code Golf, and nice first answer! Could you change c to something like s.length to make it valid for any input? \$\endgroup\$
    – emanresu A
    Commented Sep 2, 2021 at 0:10
  • \$\begingroup\$ Thanks for the suggestion, I have added a discussion of the char and int case. \$\endgroup\$
    – nils
    Commented Sep 2, 2021 at 14:10
  • \$\begingroup\$ Thanks ceilingcat, that is four bytes better! \$\endgroup\$
    – nils
    Commented Sep 10, 2021 at 21:43
  • \$\begingroup\$ Suggest r[p]<++c instead of r[p]<=c++ \$\endgroup\$
    – ceilingcat
    Commented Nov 22, 2021 at 8:43

Pyth, 32 31 bytes

Not a very optimal solution because I couldn't get the short function defintion using the L command. Feel free to help me out here



Big-Pyth Version



                str-start aeiou str-end

Try it online!

Translation Link


Husk, 27 bytes

feel free to golf down my terrible husk

had to shift the line numbers by 1 to be able to run all the test cases correctly


first line: ₃W₂m_¹ŀ

         -- implicit parameter ⁰ (last argument)
      ŀ  -- get the indices of the list (1 to len(list))
   m_¹   -- map lowercase on a copy of last argument
 W₂m_¹   -- filter by line function 2 and return indicies of truthy results
₃W₂m_¹ŀ  -- call line function 3 with two arguments (W₂m_¹ & ŀ)

second line: #"aeiou

         -- implicit parameter ⁰ (last argument)
 "aeiou  -- string "aeiou"
#"aeiou  -- get amount of occurences in list

third line: mλ▼mλa-²⁰)²

             -- implicit parameters ⁰ & ² (last and second last argument)
mλ           -- map over implicit last parameter (ŀ) 
   mλ    )²  -- map over the second last parameter
   mλ -²⁰)²  -- get the difference between the last parameter (defined in this scope) and second last parameter (defined from the first lambda)
   mλa-²⁰)²  -- get the absolute value
  ▼mλa-²⁰)²  -- get the minimum of that list

Try it online!


Excel, 198 bytes


Link to Spreadsheet


Thunno 2, 8 bytes



Żı$ṃV-AM  # Implicit input
Żı        # Map over the length range:
  $ṃV     # Indices of vowels in the input
     -AM  # Minimum of absolute differences
          # Implicit output




05AB1E, 14 bytes


Input as a list of characters.

Try it online or verify all test cases.


ā               # Push a list in the range [1, (implicit) input-length]
 ©              # Store it in variable `®` (without popping)
  žM            # Push builtin "aeiou"
    I           # Push the input-list of characters
     l          # Convert each character to lowercase
      å         # Check for each if it's in the vowel-string
       ƶ        # Multiply each by its 1-based index
        0K      # Remove all 0s
          ®     # Push the [1, length] list from variable `®`
           .x   # Get for each index the closest vowel-index
             α  # Get the absolute difference of these with the indices
                # (after which the result is output implicitly)

Arturo, 69 bytes

$->s[i:0map s=>[min map match.bounds s{(?i)[aeiou]}'x->abs-x\0i'i+1]]

Try it

$->s[                                  ; a function taking an argument s
    i:0                                ; assign 0 to i
    map s=>[                           ; map over s
        min                            ; minimum value in a list
        map                            ; map over...
        match.bounds s{(?i)[aeiou]}    ; the indices of the vowels in s
        'x->                           ; ...and assign current element t x
            abs                        ; absolute value
            -                          ; subtract
            x\0                        ; first elt of x (because match.bounds returns range)
            i                          ; and i
            'i+1                       ; increment i
    ]                                  ; end map
]                                      ; end function

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.