Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save wibisono/d8ca6aa657168502942e1f2d92a5b38d to your computer and use it in GitHub Desktop.
Save wibisono/d8ca6aa657168502942e1f2d92a5b38d to your computer and use it in GitHub Desktop.

Distance to nearest vowel

Write a function that takes a string as argument. Each character in the string will be a letter. The function should return a sequence containing the distances from each corresponding letter in the string to the nearest vowel in the string.

For example:

(nearest-vowels "aeiou") ;=> [0 0 0 0 0]  ;; if the letter is a vowel, the distance is 0
(nearest-vowels "babbb") ;=> [1 0 1 2 3]
(nearest-vowels "babbba") ;=> [1 0 1 2 1 0]

Notes:

  • All input strings will contain at least one vowel and all letters.
  • Vowels are a, e, i, o, and u.

Thanks to this site for the challenge idea where it is considered Expert level in JavaScript.

(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require
[clojure.string :as str]
[schema.core :as s]
[tupelo.chars :as chars]))
(def vowels #{\a \e \i \o \u})
(s/defn vowel? :- s/Bool
[char :- Character]
(assert (chars/lowercase? char))
(contains-elem? vowels char))
(s/defn dist-to-nearest-vowel :- s/Int
[vowel-idxs idx]
(let [dists (forv [vidx vowel-idxs]
(Math/abs (- idx vidx)))
result (apply min dists)]
result))
(s/defn vowel-dist
[src :- s/Str]
(let [letters (vec (str/lower-case src))
vowel-idxs (filter not-nil?
(forv [[idx letter] (indexed letters)]
(when (vowel? letter)
idx)))
result (forv [idx (range (count src))]
(dist-to-nearest-vowel vowel-idxs idx))]
result))
(dotest
(is= (mapv #(dist-to-nearest-vowel [3 5] %) (range 8))
[3 2 1 0 1 0 1 2])
)
(dotest
(isnt (chars/lowercase \A))
(is (chars/lowercase? \a))
(throws? (vowel? \A))
(is (vowel? \a))
(isnt (vowel? \b))
(is= (vowel-dist "abcdef") [0 1 2 1 0 1])
(is= (vowel-dist "aeiou") [0 0 0 0 0])
(is= (vowel-dist "babbb") [1 0 1 2 3])
(is= (vowel-dist "babbba") [1 0 1 2 1 0]) )
(ns nearest-vowels
(:require [clojure.test :refer [deftest are]]))
(def vowels (set (seq "aeiou")))
(defn nearest-vowels [s]
(when s
(let [chars (->> (clojure.string/lower-case s)
(seq)
(map-indexed (fn [i v] [i v])))
vowel-indices (mapv first (filter #(contains? vowels (second %)) chars))
index-fn (fn [[i _]] (map #(int (Math/abs (- i %))) vowel-indices))]
(map #(apply min (index-fn %)) chars))))
;; TESTS
(deftest nearest-vowels-test
(are [x y] (= x y)
[0 0 0 0 0] (nearest-vowels "aeiou")
[1 0 1 2 3] (nearest-vowels "babbb")
[1 0 1 2 1 0] (nearest-vowels "babbba")
[1 0 1 2 1 0] (nearest-vowels "BAbBbA")
[] (nearest-vowels "")
nil (nearest-vowels nil)))
(def vowels #{\a \e \i \o \u})
(defn nearest-vowels [s]
(let [vowel-indexes
(->> s
(clojure.string/lower-case)
(map-indexed vector)
(filter #(vowels (second %)))
(map first))]
(map-indexed (fn [i _]
(->> vowel-indexes
(map #(Math/abs (- i %)))
(apply min)))
s)))
(def vowels "aeiou")
(defn is-vowel [ch] (not (nil? (some #{ch} vowels))))
(defn abs [n] (max n (- n)))
(defn distance
"Returns the distance from the number x to the closest number in xs"
[xs x]
(apply min (map (fn [y] (abs (- y x))) xs)))
(defn nearest-vowels [string]
(let [vowel-indices (->> string
(map-indexed vector)
(filter #(is-vowel (second %)))
(map first))]
(if (not-empty vowel-indices)
(map-indexed (fn [index ch] (distance vowel-indices index)) string)
(map #{nil} string))))
(nearest-vowels "babbba") ;; (1 0 1 2 1 0)
(nearest-vowels "hjkl") ;; (nil nil nil nil)
(def vowels (set "aeiou"))
(defn next-vowels [s]
(loop [s s, n 0, was? false, dist []]
(if s
(let [vowel? (some? (vowels (first s)))
n (if vowel? 0 (inc n))
found? (some true? [was? vowel?])]
(recur (next s) n found? (conj dist [n found?])))
dist)))
(defn nearest-vowels [s]
(let [next-left (next-vowels s)
next-right (next-vowels (clojure.string/reverse s))]
(vec (map (fn [[dist1 was-vowel1?] [dist2 was-vowel2?]]
(cond
(and was-vowel1? was-vowel2?) (min dist1 dist2)
was-vowel1? dist1
:else dist2))
next-left (reverse next-right)))))
(nearest-vowels "aeiou") ;=> [0 0 0 0 0]
(nearest-vowels "babbb") ;=> [1 0 1 2 3]
(nearest-vowels "babbba") ;=> [1 0 1 2 1 0]
(ns functional-tv-puzzles.-2020.nearest-376)
(def vowels (set "aeiou"))
(defn paths-> [xs]
(let [forward (fn fw [[x & xs :as all], acc]
(if x
(fw xs (conj acc all))
acc))]
(forward xs [])))
(defn <-paths [xs]
(reverse (paths-> (reverse xs))))
(defn paths [xs]
(map vector (paths-> xs) (<-paths xs)))
(defn distance [path]
(let [vdist (fn dist [[x & xs] n]
(cond
(and x (vowels x)) n
x (dist xs (inc n))
:else Integer/MAX_VALUE ))]
(vdist path 0)))
(defn nearest-vowels [xs]
(->> xs seq paths
(reduce (fn [acc [left right]]
(conj acc (min (distance left)
(distance right))))
[])))
(def vowels (into #{} "aeiou"))
(defn border-distances
"Given a string returns a seq containing the distance of
each character to its nearest border.
Example : (border-distances \"xxxxx\") => (1 2 3 2 1)"
[s]
(let [l (count s)
mid-range (reverse (range 1 (inc (/ l 2))))]
(if (even? l)
(into mid-range mid-range)
(into mid-range (rest mid-range)))))
(defn nearest-vowels
"Given a string return a sequence containing the distances from each
corresponding letter in the string to the nearest vowel in the string."
[s]
(let [parts (partition-by vowels s)]
(->> parts
(map-indexed (fn [i xs]
(let [count-range (range 1 (inc (count xs)))]
(cond
;; its a vowel
(vowels (first xs)) [0]
;; its the partition next to the left border
(= i 0) (reverse count-range)
;; its the partition next to the right border
(and (= i (dec (count parts)))) count-range
;; it is a partition in the middle
:else (border-distances xs)))))
(apply concat))))
;; shorter version
(defn nearest-vowels [s]
(let [vows-pos (keep-indexed (fn [i c] (when (vowels c) i)) s)] ;; collect all vowels positions
(->> (range (count s))
(map (fn [i] ;; grab then min distance from this pos to a vowel position
(apply min (map (fn [v] (Math/abs (- i v))) vows-pos)))))))
(defn nearest-vowels [letters]
(let [vowels (set "aeiou")
lc #(clojure.string/lower-case %)
vowel-indices (keep-indexed #(if (vowels %2) %1) (lc letters))]
(map-indexed
(fn [ind item]
(if (vowels item) 0
(reduce min (map #(Math/abs (- ind %)) vowel-indices)))) (lc letters))))
(defn nearest-vowels
"Return distances from letters in s to their nearest vowels in s"
[s]
(let [mivs (map-indexed vector s) ;; sequence of [index letter]
vowels #{\a \e \i \o \u}]
(letfn [(abs [n] (if (neg? n) (- n) n))
(distance [[l1pos _] [l2pos]] (abs (- l2pos l1pos)))
(vwls [mivstr] (filter #(vowels (second %)) mivstr))
(nearest-to [letter]
(apply min ;; smallest distance
(map (partial distance letter) (vwls mivs))))]
(map nearest-to mivs))))
(defn nearest-vowels [s]
(let [vowels #{\a \e \i \o \u}
vowels-idx (mapcat (fn [i ch] (when (vowels ch) [i]))
(range)
s)
handle-range (fn [from to]
(cond
(nil? from) (range to 0 -1)
(nil? to) (range 0 (- (count s) from))
:else (map #(Math/min (- % from) (- to %))
(range from to))))
]
(mapcat handle-range
(cons nil vowels-idx)
(concat vowels-idx [nil]))))
(defn distance_to_nearest_vowel
[s]
(flatten
(reduce
(fn [[result consonant-count] c]
(cond
(= \- c) ;; last char?
(conj result (range 1 consonant-count))
;; if c is a vowel then add two entries to `result`
;; 1. a '(0) for the vowel just encounted
;; 2. a list for the `run` of consonants just traversed. Might be a `()`
(#{\a \e \i \u \o} c)
(let [r (range 1 consonant-count)
rev-r (reverse r)
r' (if (empty? result) rev-r (map min r rev-r))]
[(conj result r' '(0)) 1]) ;; also reset the count
:else
[result (inc consonant-count)])) ;; continue counting constanants
[[] 1]
(str s \-))))
(defn shiftinc
[before]
(let [upped (map #(when % (inc %)) before)
right (concat '(nil ) (butlast upped))
left (concat (rest upped) '(nil))]
(->> (map vector before right left)
(map #(when (not-every? nil? %)
(apply min (remove nil? %)))))))
(defn nearest-vowels
[string]
(let [vowels (map #{\a \e \i \o \u} string)]
(loop [distance (map #(when (some? %) 0) vowels)]
(if (not-any? nil? distance)
distance
(recur (shiftinc distance))))))
(defn distances [i len]
(concat (range i -1 -1)
(range 1 (- len i))))
(defn nearest-vowels [s]
(apply map min
(keep-indexed (fn [i c]
(when (#{\a \i \e \o \u} c)
(distances i (count s))))
s)))
(defn get-chunks [s]
(let [vowels (set "aeiou")
is-vowel? (fn [c] (contains? vowels c))
chunks (partition-by is-vowel? s)
indexer (fn [idx chk]
{:first? (= idx 0)
:last? (= idx (dec (count chunks)))
:chars chk})
describe (fn [m]
(let [dists (range 1 (inc (count (:chars m))))]
(merge m
{:vowel? (is-vowel? (first (:chars m)))
:l-dists dists
:r-dists (reverse dists)})))]
(->> chunks
(map-indexed indexer)
(map describe))))
(defn distances [chk]
(cond
(:vowel? chk) (repeat (count (:chars chk)) 0)
(:first? chk) (:r-dists chk)
(:last? chk) (:l-dists chk)
:else (for [pr (partition 2 (interleave (:l-dists chk) (:r-dists chk)))]
(apply min pr))))
(defn nearest-vowels [s]
(mapcat distances
(get-chunks s)))
(def vowel? #{\a \e \i \o \u})
(defn distance-to-vowel-left [s]
(reduce (fn [dists ch]
(conj dists (if (vowel? ch)
0
(when-let [dist (peek dists)]
(inc dist)))))
[]
s))
(defn distance-to-vowel-right [s]
(-> s reverse distance-to-vowel-left reverse))
(defn min-dist [& ds]
(apply min (filter some? ds)))
(defn nearest-vowels [s]
(mapv min-dist (distance-to-vowel-left s) (distance-to-vowel-right s)))
(ns purelyfunctional-newsletters.issue-376
(:require [clojure.test :refer :all]))
(def all-vowels (set "aeiou"))
(defn vowel? [c]
(all-vowels c))
(defn min-distance-between [x xs]
(->> xs
(map #(-> (- x %) Math/abs))
(apply min)))
(defn nearest-vowels [s]
{:pre [(some all-vowels s)]}
(let [letters-indexed (map-indexed vector s)
vowel-indexes (->> letters-indexed
(filter #(vowel? (second %)))
(map first))]
(->> letters-indexed
(map (fn [[letter-idx letter]]
(if (vowel? letter)
0
(min-distance-between letter-idx vowel-indexes)))))))
(deftest nearest-vowels-testing
(is (= [0 0 0 0 0]
(nearest-vowels "aeiou")))
(is (= [1 0 1 2 3]
(nearest-vowels "babbb")))
(is (= [1 0 1 2 1 0]
(nearest-vowels "babbba"))))
(def pos-integers (iterate inc 1))
(def vowels #{\a \e \i \o \u})
(defn distance
[index]
(concat (reverse (take index pos-integers))
[0]
pos-integers))
(defn nearest-vowels
[s]
(apply map min (for [i (range (count s))
:when (vowels (get s i))]
(take (count s) (distance i)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment