# Find me vowels near you

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.)

• 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. Aug 30 '21 at 15:49
• hey anyone know if we can answer our own question? Aug 30 '21 at 16:47
• @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) Aug 30 '21 at 16:49
• @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. Aug 30 '21 at 16:51
• Would a value like false/null/undefined be a valid output for an empty string input? Aug 31 '21 at 8:22

# Jelly, 10 bytes

e€ØcTạⱮJṂ€


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

Try it online!

### How?

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

⌊/∘|⍳∘⍴∘.-∘⍸'aeiou'∊⍨⎕C


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

(\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. a=>a.map((_,x)=>a.map(m=c=>m=(v=x--<0?~x:-~x)>m|~2130466>>c&1?m:v)|m)  Try it online! ### Commented 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()  • How does the magic constant 2130466 work? Aug 31 '21 at 8:47 • @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). Aug 31 '21 at 8:51 # 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! • It looks to save you 3 bytes to use a lambda instead, with enumerate to loop. Aug 31 '21 at 6:23 • @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 – ovs Aug 31 '21 at 8:18 # 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)\$$

a%b=sum[b+1|all(/=a)"aeiouAEIOU"]
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

 bbabbabb
789012012


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

bbabbabb
210210987


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

bbabbabb
21011012


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.

function(x)Map(function(i)min(abs(i-el(gregexpr("[aeiou]",x,T)))),seq(l=nchar(x)))


Try it online!

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

Previous solution (with explanation):

### R, 83 bytes

function(x)apply(abs(outer(seq(l=nchar(x)),el(gregexpr("[aeiou]",x,T)),-)),1,min)


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
}

• Nice! -1 byte by returning a list instead of a vector. Aug 30 '21 at 21:19

# jq, 7369 62 bytes

-7 bytes thanks to Michael Chatiskatzi!

[explode[]%32]|keys[]as$y|[indices(1,5,9,15,21)[]-$y|fabs]|min


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

• 62 bytes Sep 7 '21 at 12:23
• @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 :)
– ovs
Sep 7 '21 at 13:03

# Japt v2.0a0, 12 bytes

¬£ð\v maY rm

¬£ð\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


# J, 36 34 bytes

i.@#<./@(|@-/~I.)'aeiou'e.~tolower


Try it online!

-2 thanks to FrownyFrog

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

• 34 Aug 30 '21 at 22:33
• Thanks @FrownyFrog! Good to see you around. Aug 30 '21 at 23:58

a=>(g=a=>a.map(n=>p=/[aoeui]$/i.test(n)?0:++p>n?n:p,p=1/0).reverse())(g(a))  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=>(g=a=>a.map(n=>p=++p>n?n:/[^aoeui]/i.test(n)&&p,p=1/0).reverse())(g(a))  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 lMin@Abs@Pick[j-#,Capitalize@l,"A"|"E"|"I"|"O"|"U"]&/@(i=0;j=i++&/@l)  Try it online! Input a character list. # JavaScript, 73 bytes Takes input as an array of characters. a=>a.map((b,x)=>a.map(c=>b=!/[aeiou]/i.test(c,y=x--<0?~x:-~x)|y>b?b:y)|b)  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. • I feel your pain. tsh and Arnauld are very good at this. Aug 31 '21 at 20:04 • Hey! I have my moments, too, @emanresuA! :p Sep 1 '21 at 9:09 • So do I Sep 1 '21 at 9:11 # Retina, 63 bytes iL$(?=(.*?)[aeiou])?.(?<=[aeiou](.*?))?
$.1;$.2
%(N\d+
0L\d+


Try it online! Link includes test cases. Explanation:

iL$(?=(.*?)[aeiou])?.(?<=[aeiou](.*?))?$.1;$.2  Looping over each letter, look for nearby vowels. %(  Loop over each result separately. N\d+ 0L\d+  Take the minimum. (I feel there should be a shorter way to do this, but I can't think what is might be.) # Vyxal, 11 bytes ẏƛ?k∨v↔T-ȧg  Try it Online! Independently rediscovered Jonathan Allan's method. ẏ # Range 0...a.length - 1 ƛ # Map... v↔ # Listifiy and remove characters not in... k∨ # Vowels ? # From input T # Truthy indices (indices of vowels in input) - # Subtract (distances) ȧ # Absolute value these (absolute distances) g # Minimum of these (closest value)  # PHP < 7.1.0 -F , 125 bytes for(;$c=($a=$argn)[$i++];$r[]=$p)for($j=0,$p=-1;$p<0;$j=$j<0?-$j:-$j-1)!stripos(_aeiou,$a[$i+$j-1])?:$p=abs($j);var_dump($r);


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 a=>[...a].map((_,B,V)=>Math.min(...V.map((c,C)=>/[aeiou]/i.test(c)?C>B?C-B:B-C:1/0)))  ## 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 • 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. – Neil Sep 1 '21 at 23:35 • @Neil : alright : so first obviously works (saved 3 bytes). 2nd knocked off 2 bytes. 3rd knocked off (5 bytes). Thanks a bunch Sep 2 '21 at 2:58 # Charcoal, 20 bytes ＩＥθ⌊↔⁻κΦＬθ№aeiou↧§θλ  Try it online! Link is to verbose version of code. Explanation:  θ Input string Ｅ Map over characters θ Input string Ｌ Length Φ Filter over implicit range §θλ Inner character ↧ Lowercase № Is contained in aeiou Lowercase vowels ⁻ Vectorised subtract κ Current index ↔ Vectorised absolute value ⌊ Minimum Ｉ 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! # Ungolfed # 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! • 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 Aug 30 '21 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

->s{w=s.size;s.chars.map{|c|w=[w+=1,s=~/[aeiou]/i||w].min;s[0]='';w}}


Try it online!

### Break it down bro

->s{w=s.size;


Initialize with the worst case (will never happen)

    s.chars.map{|c|


For every character of the input string

        w=[w+=1,s=~/[aeiou]/i||w].min;


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

            s[0]='';w}}


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

# Python3, 198 bytes

Golfed:

def f(s):
v='aeiouAEIOU';l=[];r=[];L=R=len(s:=s.lower())-2
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)

Non-golfed:

def dTNV(s):
s=s.lower()
left_min=[]
right_min=[]
distl=distr=len(s)-2
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
left_min.append(distl)
right_min.append(distr)
return [min(left_min[i],right_min[-(i+1)]) for i in range(len(s))]

• 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. Sep 2 '21 at 16:43
• 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! Sep 2 '21 at 16:48
• Variable names like left_min and distl can be shortened to save a lot of bytes Sep 2 '21 at 17:25
• 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. Sep 2 '21 at 17:50

# Python 3, 174 bytes

def f(s):
o=[]
for c,l in enumerate(s):
i,j=c,0
while 1:
if i in range(len(s))and s[i]in'aeiouAEIOU':
o+=[abs(c-i)]
break
j+=1
i+=j*(j%2*2-1)
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.

• 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.
– xnor
Sep 2 '21 at 22:52
• 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! Sep 3 '21 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 ]
}
r[p++]=c++;
}
//iterate backwards counting distance and store lower value from both iterations in r
for(--p;p>=0;--p) {
if(r[p]<=c) {
c=r[p];
} else {
r[p]=c;
}
++c;
}
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;


by

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:

#include<iostream>
#include<string>
#include<vector>

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;
}
$$$$

• Welcome to Code Golf, and nice first answer! Could you change c to something like s.length to make it valid for any input? Sep 2 '21 at 0:10
• Thanks for the suggestion, I have added a discussion of the char and int case.
– nils
Sep 2 '21 at 14:10
• Thanks ceilingcat, that is four bytes better!
– nils
Sep 10 '21 at 21:43
• Suggest r[p]<++c instead of r[p]<=c++ Nov 22 '21 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

## Code

DtZJrZ0R.ehSmadksmxdcJ1"aeiou"J


## Big-Pyth Version

def
tail
zero-var

implicit-assign
auto-var
lower
zero-var
0

return
enumerate-map
sorted
map
absolute-difference
map-var
enumerate-map-ind
flatten-once
map
ind-all-occurrences
map-var
chop-into-size-n
auto-var
1
str-start aeiou str-end
auto-var


Try it online!

# 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

₃W₂m_¹ŀ
#"aeiou
mλ▼mλa-²⁰)²


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

=LET(x,LEN(A1),a,SEQUENCE(x),b,IFERROR(FIND(MID(A1,a,1),"aeiouAEIOU")^0*a,99999),d,SEQUENCE(x^2,,x),e,MOD(d,x)+1,f,INT(d/x),g,INDEX(ABS(b-TRANSPOSE(a)),e,f),IF(A1="","",FILTER(SORTBY(g,f,,g,),e=1)))


# 05AB1E, 14 bytes

ā©žMIlSåƶ0K®.xα


Input as a list of characters.

Explanation:

ā               # 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)
`