loading...

Daily Challenge #205 - Consonant String Value

thepracticaldev profile image dev.to staff ・1 min read

Given a lowercase string that has alphabetic characters only and no spaces, implement a function that will return the highest value of consonant substrings. Consonants are any letters of the alphabet except "aeiou".

We shall assign the following values: a = 1, b = 2, c = 3, .... z = 26.

For example, for the word "zodiacs", let's cross out the vowels. We get: "z, d, cs". The values are z = 26, d = 4 and cs = 3 + 19 = 22. The highest is 26.
solve("zodiacs") = 26

For the word "strength", solve("strength") = 57
-- The consonant substrings are: "str" and "ngth" with values "str" = 19 + 20 + 18 = 57 and "ngth" = 14 + 7 + 20 + 8 = 49. The highest is 57.

Tests

solve("chruschtschov") => 80
solve("khrushchev")
solve("strength")
solve("catchphrase")
solve("twelfthstreet")
solve("mischtschenkoana")

Good luck!


This challenge comes from KenKamau on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

pic
Editor guide
 

Scala

  lazy val values = "abcdefghijklmnopqrstuvwxyz".toList.zip(Stream.from(1)).toMap

  def solve (str: String): Int = {
    ("[aeiou]".r.split(str).toList map evaluate).max
  }

  def evaluate (str: String): Int = {
    (str map (values.getOrElse(_, 0))).sum
  }

  solve("zodiacs")          // 26
  solve("chruschtschov")    // 80
  solve("khrushchev")       // 38
  solve("strength")         // 57
  solve("catchphrase")      // 73
  solve("twelfthstreet")    // 103
  solve("mischtschenkoana") // 80
 

I've always appreciated Scala solutions for their mixed-notation to function-call chaining, it's truly bizarre. 😲

...(str map ([expr]) // prefix-notation chaining...
...[expr]).sum // object-notation chaining...
 

Javascript solution

const values = [...Array(26).keys()]
  .map(i => String.fromCharCode(i + 97))
  .reduce((o, l, i) => ({ ...o, [l]: i + 1 }), {});

const groupValue = group => 
  group.split("").reduce((acc, val) => acc + values[val], 0);

const solve = word =>
  word
    .split(/[aeiou]/)
    .filter(e => e.length)
    .reduce((acc, val) => (groupValue(val) > acc ? groupValue(val) : acc), 0);

const tests = [
  "zodiacs", //26
  "chruschtschov", //80
  "strength", //57
  "catchphrase", //73
  "twelfthstreet", //103
  "mischtschenkoana" //80
];

console.log(tests.map(solve));
 

Nice! Here's my implementation:

const solve = word => word.split(/[uoiea]/)
                          .map(s => s.split('')
                                     .reduce((acc, c) => acc + (c.charCodeAt(0) - 96), 0))
                          .sort((a, b) => b-a)[0];
 

Very nice, I wasn't aware of the c.charCodeAt(0) - 96 rule, didn't work with chars very much in all these years to be honest.

It only works with lowercase a to z, because UTF-16 represents them as contiguous code points, starting at 97.

 

Here is a Python one-liner

import re
solve = lambda s : max([sum([ord(letter)-ord('a')+1 for letter in consOnly]) for consOnly in re.split("a|e|i|o|u",s)])

print(solve("zodiacs")) # output : 26
print(solve("chruschtschov")) # output : 80
print(solve("rhythm")) # output : 92
 

Elixir

defmodule Challenges do
  import Enum, only: [ map: 2, max: 1, sum: 1 ]

  def solve(str) do
    String.split(str, ~r{[aeiou]}, trim: true)
      |> map(&_calculate_value/1)
      |> max
  end

  defp _calculate_value(str) do
    String.to_charlist(str)
      |> map(&(&1 - 96))
      |> sum
  end
end
 

Java Streams

public int solve(String input) {
   return Arrays.stream(input.split("[aeiou]"))
                .map(s -> s.chars().map(ch -> ch - 96).sum())
                .reduce(0, (a, b) -> a > b ? a : b);
}
 

Rust:

pub fn solve(text: &str) -> u32 {
    text.split(|c| match c {
        'a' | 'e' | 'i' | 'o' | 'u' => true,
        _ => false,
    }).map(|seq| {
        seq.chars().map(|c| (c as u32) - ('a' as u32) + 1u32).sum::<u32>()
    }).max().unwrap_or(0)
}
 

C++ solution using simple for-loop


int solve(string s){
    int tempMax = 0, maxSoFar = 0;
    for(int i=0;i<s.length();i++){
        if(s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u'){
            maxSoFar = max(tempMax, maxSoFar);
            tempMax = 0;
        }
        else{
            tempMax += s[i]-'a'+1;
        }
    }
    return max(maxSoFar, tempMax);
}
 

Go, single-pass

package value

func ConsonantStringValue(s string) int {
    highest := 0
    total := 0
    for _, c := range s {
        if isVowel(c) {
            highest = max(highest, total)
            total = 0
            continue
        }
        total += toValue(c)
    }
    highest = max(highest, total)
    return highest
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func isVowel(c rune) bool {
    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'
}

func toValue(c rune) int {
    return int(c) - 96
}
 

C

#include <stdio.h>

int isVowel(const char letter);
int highestConsonantSubstring(const char* string);

int main(void) {
    printf("%d\n", highestConsonantSubstring("strength"));
    printf("%d\n", highestConsonantSubstring("chruschtschov"));

    return 0;
}

int isVowel(const char letter) {
    switch (letter) {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
            return 1;

        default:
            return 0;
    }
}

int highestConsonantSubstring(const char* string) {
    const char* letter = string;

    unsigned int highest = 0;
    unsigned int current = 0;

    for (const char* letter = string; *letter; letter++) {
        if (!isVowel(*letter)) {
            current += *letter - 96;
            continue;
        }

        if (highest < current) {
            highest = current;
        }

        current = 0;
    }

    return highest;
}
 

This was fun, Ruby solution:

VOWELS = /[aeiou]/

def solve(s)
  s.
    chars.
    chunk { |c| c !~ VOWELS }.
    filter_map { |b, cs| b && cs.reduce(0) { |s, c| s + c.ord - 96 } }.
    max
end

solve("zodiacs")
#=> 26
solve("strength")
#=> 57
solve("chruschtschov")
#=> 80

Alternatively there's also a possible solution with String#scan:

s.
  scan(/([^aeiou]+)/).
  map { |a| a.first.chars.reduce(0) { |s, c| s + c.ord - 96 } }.
  max
 

Also made an OCaml version:

let vowels = [ 'a'; 'e'; 'i'; 'o'; 'u' ]

let solve s =
  match s with
  | "" -> None
  | _ ->
    s
    |> String.split_on_chars ~on:vowels
    |> List.map ~f:(fun s ->
           s |> String.fold ~init:0 ~f:(fun s c -> s + Char.to_int c - 96))
    |> List.max_elt ~compare:Int.compare