## Reverse Vowels

### June 4, 2019

Our definition of vowel is simplistic:

`(define (vowel? c) (member (char-downcase c) '(#\a #\e #\i #\o #\u)))`

We make two passes over the input, collecting vowels on the first pass (in `filter` and rewriting on the second pass (in `loop`):

```(define (reverse-vowels str)
(let* ((cs (string->list str)) (vs (reverse (filter vowel? cs))))
(let loop ((cs cs) (vs vs) (zs (list)))
(cond ((null? cs) (list->string (reverse zs)))
((vowel? (car cs))
(let ((f (if (char-upper-case? (car cs)) char-upcase char-downcase)))
(loop (cdr cs) (cdr vs) (cons (f (car vs)) zs))))
(else (loop (cdr cs) vs (cons (car cs) zs)))))))```

Here are our two examples:

```> (reverse-vowels "HELLO world")
"HOLLO werld"
> (reverse-vowels "Programming PRAXIS")
"Prigramming PRAXOS"```

The student who asked the question was trying to solve the problem in a single pass using two pointers, one traversing the string left-to-right and the other traversing the string right-to-left, but got confused. I think the two-pass approach is simpler and leads to code that is more obviously correct. Here is my version of the student’s algorithm, which demonstrates a different way to handle the case-correction part of the task:

```(define (reverse-vowels str)
(define (fix-case x y)
(if (char-upper-case? x)
(char-upcase y)
(char-downcase y)))
(let loop ((lo 0) (hi (- (string-length str) 1)))
(cond ((< hi lo) str)
((and (vowel? (string-ref str lo))
(vowel? (string-ref str hi)))
(let ((temp (string-ref str lo)))
(string-set! str lo
(fix-case temp (string-ref str hi)))
(string-set! str hi
(fix-case (string-ref str hi) temp)))
(loop (+ lo 1) (- hi 1)))
((not (vowel? (string-ref str lo))) (loop (+ lo 1) hi))
((not (vowel? (string-ref str hi))) (loop lo (- hi 1)))
(else (loop (+ lo 1) (- hi 1))))))```

And here again are our two examples:

```> (reverse-vowels "HELLO world")
"HOLLO werld"
> (reverse-vowels "Programming PRAXIS")
"Prigramming PRAXOS"```

You can run the program at https://ideone.com/12nlr2.

Advertisements

Pages: 1 2

### 9 Responses to “Reverse Vowels”

1. chaw said

I decided to use a functional style instead of the perhaps more
obvious in-place replacement of characters in an array. My program
(written without peeking at the solution) ended up being almost the
same as the first one by programmingpraxis, except for the slight
optimization of avoiding a couple of reverses. Here it is for
completeness sake.

``` (import (scheme base) (scheme write) (scheme char)) ;; Equivalent to (reverse (filter pred lst)) but avoids extra reversing. (define (reverse-filter pred lst) (let loop ((lst lst) (r '())) (if (null? lst) r (loop (cdr lst) (if (pred (car lst)) (cons (car lst) r) r))))) (define vowel? (let ((vs (string->list "AaEeIiOoUu"))) (lambda (c) (memq c vs)))) ;; Replace the i'th vowel in str (counting from the left) with the ;; i'th vowel counting from the right (for all valid i), preserving ;; the case of the original vowel. (define (reverse-vowels str) (let ((cs (string->list str))) (let loop ((cs cs) (rv (reverse-filter vowel? cs)) (r '())) (if (null? cs) (list->string (reverse r)) (if (vowel? (car cs)) (loop (cdr cs) (cdr rv) (cons ((if (char-upper-case? (car cs)) char-upcase char-downcase) (car rv)) r)) (loop (cdr cs) rv (cons (car cs) r))))))) (write (map reverse-vowels '("Hello, World!" "Programming PRAXIS"))) (newline) ("Hollo, Werld!" "Prigramming PRAXOS") ```

2. Steve said

Mumps version

```
Code:  This is written in the form of variables which contain code and are executed.
Z is the driver variable, which executes the other variables
Z2 gets the string and defines the vowels
Z3 scans the string for vowels and places them in a stack
Z4 scans the string for vowels and replaces them with the vowels from the stack
Z5 prints the new string

Z="X Z2 X:STR]"" Z3,Z4,Z5"

Z2="R !,"STRING: ",STR S VWLS="AEIOUY""

Z3="K V F I=1:1:\$L(STR) S LTR=\$E(STR,I) I VWLS[LTR S V(\$I(V,-1))=LTR"

Z4="S V="" F I=1:1:\$L(STR) S LTR=\$E(STR,I) I VWLS[LTR S V=\$O(V(V)),VOW=V(V) K V(V) S \$E(STR,I)=VOW"

Z5="W !,STR"

---

Run:

DEVESS>X Z

STRING: HELLO, WORLD!

HOLLO, WERLD!

DEVESS>X Z

STRING: PROGRAMMING PRAXIS

PRIGRAMMING PRAXOS

```
3. Smith said
```s = "HELLO world"
ns = list(s)
vowels = 'aeiouAEIOU'

first, last = 0, len(s)-1
while first <= last:
while (s[first] not in vowels):
first += 1
if first == last: break
while (s[last] not in vowels):
last -= 1
if first == last: break

ns[last] = s[first].upper() if ns[last].isupper() else s[first].lower()
ns[first] = s[last].upper() if ns[first].isupper() else s[last].lower()

first += 1
last -= 1

print(''.join(ns))
# HOLLO werld
```
4. Globules said

A Haskell version.

```import Data.Bool (bool)
import Data.Char (isLower, toLower, toUpper)

-- Reverse the order of vowels in a string, maintaining the case of the original
-- letter.
slewov :: String -> String
slewov = revsub isVowel updCase
where isVowel c = c `elem` "aeiouAEIOU"
updCase x = bool toUpper toLower (isLower x)

revsub :: (a -> Bool) -> (a -> a -> a) -> [a] -> [a]
revsub prd upd xs = subst prd upd xs (reverse \$ filter prd xs)

subst :: (a -> Bool) -> (a -> a -> a) -> [a] -> [a] -> [a]
subst prd upd = go
where go (x:xs) (y:ys) | prd x     = upd x y : go xs ys
| otherwise =       x : go xs (y:ys)
go xs [] = xs
go [] ys = ys

main :: IO ()
main = do
putStrLn \$ slewov "HELLO world"
putStrLn \$ slewov "Programming PRAXIS"
```
```\$ ./vowels
HOLLO werld
Prigramming PRAXOS
```
5. Steve said

Klong version

```Code:
Klong 20190209
:" Reverse vowels"
l::[]
f1::{[len r s v]; len::#s::x; r::""; v::"AEIOUYaeiouy"; {x<len}{f2(s@x; v); x+1}:~0; {x<len}{r::r,f3(s@x; v); x+1}:~0; r}
f2::{:[#y?x; l::(\$x),l; ""]}
f3::{[r2]; :[#y?x; {r2::*l; l::1_l; r2}(); x]}

Run:
f1'["HELLO, WORLD!" "PROGRAMMING PRAXIS"]
["HOLLO, WERLD!" "PRIGRAMMING PRAXOS"]

```
6. Bill Wood said

Rust version:

```struct RevVowelIter<'a> {
it: std::iter::Rev<std::str::Chars<'a>>,
}
impl<'a> Iterator for RevVowelIter<'a> {
type Item = char;

fn next(&mut self) -> Option<Self::Item> {
while let Some(c) = self.it.next() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' |
'A' | 'E' | 'I' | 'O' | 'U' => return Some(c),
_ => (),
}
}
None
}
}
impl<'a> RevVowelIter<'a> {
fn new(s: &'a str) -> Self {
RevVowelIter { it: s.chars().rev() }
}
}

fn rev_vowels(st: &str) -> String {
let mut s = "".to_string();
let mut v = RevVowelIter::new(st);
for c in st.chars() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' => s.push(v.next().unwrap().to_ascii_lowercase()),
'A' | 'E' | 'I' | 'O' | 'U' => s.push(v.next().unwrap().to_ascii_uppercase()),
_ => s.push(c),
}
}
s
}

fn main() {
assert_eq!("HOLLO werld", rev_vowels("HELLO world"));
assert_eq!("Prigramming PRAXOS", rev_vowels("Programming PRAXIS"));
}
```
7. Bill Wood said

Rust version:

```struct RevVowelIter<'a> {
it: std::iter::Rev<std::str::Chars<'a>>,
}
impl<'a> Iterator for RevVowelIter<'a> {
type Item = char;

fn next(&mut self) -> Option<Self::Item> {
while let Some(c) = self.it.next() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' |
'A' | 'E' | 'I' | 'O' | 'U' => return Some(c),
_ => (),
}
}
None
}
}
impl<'a> RevVowelIter<'a> {
fn new(s: &'a str) -> Self {
RevVowelIter { it: s.chars().rev() }
}
}

fn rev_vowels(st: &str) -> String {
let mut s = "".to_string();
let mut v = RevVowelIter::new(st);
for c in st.chars() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' => s.push(v.next().unwrap().to_lowercase().next().unwrap()),
'A' | 'E' | 'I' | 'O' | 'U' => s.push(v.next().unwrap().to_uppercase().next().unwrap()),
_ => s.push(c),
}
}
s
}

fn main() {
assert_eq!("HOLLO werld", rev_vowels("HELLO world"));
assert_eq!("Prigramming PRAXOS", rev_vowels("Programming PRAXIS"));
}
```
8. Bill Wood said

Rust version without custom iterator

```fn rev_vowels(st: &str) -> String {
let mut s = "".to_string();
let mut v = st.chars().rev().filter(|c| "aeiouAEIOU".find(*c).is_some());
for c in st.chars() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' => s.push(v.next().unwrap().to_ascii_lowercase()),
'A' | 'E' | 'I' | 'O' | 'U' => s.push(v.next().unwrap().to_ascii_uppercase()),
_ => s.push(c),
}
}
s
}

fn main() {
assert_eq!("HOLLO werld", rev_vowels("HELLO world"));
assert_eq!("Prigramming PRAXOS", rev_vowels("Programming PRAXIS"));
}
```
9. Daniel said

Here’s a solution in Python.

```def reverse_vowels(string):
VOWELS = 'AaEeIiOoUu'
subs = [x for x in string if x in VOWELS]
chars = [subs.pop().lower() if x in VOWELS else x for x in string]
chars = [c if s.islower() else c.upper() for s, c in zip(string, chars)]
return ''.join(chars)

print(reverse_vowels('HELLO world'))
print(reverse_vowels('Programming PRAXIS'))
```

Output:

```HOLLO werld
Prigramming PRAXOS
```