Daily Challenge #47 - Alphabets

twitter logo ・1 min read

Daily Challenge (119 Part Series)

1) Daily Challenge #1 - String Peeler 2) Daily Challenge #2 - String Diamond 3 ... 117 3) Daily Challenge #3 - Vowel Counter 4) Daily Challenge #4 - Checkbook Balancing 5) Daily Challenge #5 - Ten Minute Walk 6) Daily Challenge #6 - Grandma and her friends 7) Daily Challenge #7 - Factorial Decomposition 8) Daily Challenge #8 - Scrabble Word Calculator 9) Daily Challenge #9 - What's Your Number? 10) Daily Challenge #10 - Calculator 11) Daily Challenge #11 - Cubic Numbers 12) Daily Challenge #12 - Next Larger Number 13) Daily Challenge #13 - Twice Linear 14) Daily Challenge #14 - Square into Squares 15) Daily Challenge #15 - Stop gninnipS My sdroW! 16) Daily Challenge #16 - Number of People on the Bus 17) Daily Challenge #17 - Double Trouble 18) Daily Challenge #18 - Triple Trouble 19) Daily Challenge #19 - Turn numbers into words 20) Daily Challenge Post #20 - Number Check 21) Daily Challenge #21 - Human Readable Time 22) Daily Challenge #22 - Simple Pig Latin 23) Daily Challenge #23 - Morse Code Decoder 24) Daily Challenge #24 - Shortest Step 25) Daily Challenge #25 - Double Cola 26) Daily Challenge #26 - Ranking Position 27) Daily Challenge #27 - Unlucky Days 28) Daily Challenge #28 - Kill the Monster! 29) Daily Challenge #29 - Xs and Os 30) Daily Challenge #30 - What is the price? 31) Daily Challenge #31 - Count IPv4 Addresses 32) Daily Challenge #32 - Hide Phone Numbers 33) Daily Challenge #33 - Did you mean...? 34) Daily Challenge #34 - WeIrD StRiNg CaSe 35) Daily Challenge #35 - Find the Outlier 36) Daily Challenge #36 - Let's go for a run! 37) Daily Challenge #37 - Name Swap 38) Daily Challenge #38 - Middle Name 39) Daily Challenge #39 - Virus 40) Daily Challenge #40 - Counting Sheep 41) Daily Challenge #41 - Greed is Good 42) Daily Challenge #42 - Caesar Cipher 43) Daily Challenge #43 - Boardgame Fight Resolver 44) Daily Challenge #44 - Mexican Wave 45) Daily Challenge #45 - Change Machine 46) Daily Challenge #46 - ??? 47) Daily Challenge #47 - Alphabets 48) Daily Challenge #48 - Facebook Likes 49) Daily Challenge #49 - Dollars and Cents 50) Daily Challenge #50 - Number Neighbor 51) Daily Challenge #51 - Valid Curly Braces 52) Daily Challenge #52 - Building a Pyramid 53) Daily Challenge #53 - Faro Shuffle 54) Daily Challenge #54 - What century is it? 55) Daily Challenge #55 - Building a Pile of Cubes 56) Daily Challenge #56 - Coffee Shop 57) Daily Challenge #57 - BMI Calculator 58) Daily Challenge #58 - Smelting Iron Ingots 59) Daily Challenge #59 - Snail Sort 60) Daily Challenge #60 - Find the Missing Letter 61) Daily Challenge #61 - Evolution Rate 62) Daily Challenge #62 - Josephus Survivor 63) Daily Challenge #63- Two Sum 64) Daily Challenge #64- Drying Potatoes 65) Daily Challenge #65- A Disguised Sequence 66) Daily Challenge #66- Friend List 67) Daily Challenge #67- Phone Directory 68) Daily Challenge #68 - Grade Book 69) Daily Challenge #69 - Going to the Cinema 70) Daily Challenge #70 - Pole Vault Competition Results 71) Daily Challenge #71 - See you next Happy Year 72) Daily Challenge #72 - Matrix Shift 73) Daily Challenge #73 - ATM Heist 74) Daily Challenge #74 - Free Pizza 75) Daily Challenge #75 - Set Alarm 76) Daily Challenge #76 - Bingo! (or not...) 77) Daily Challenge #77 - Bird Mountain 78) Daily Challenge #78 - Number of Proper Fractions with Denominator d 79) Daily Challenge #79 - Connect Four 80) Daily Challenge #80 - Longest Vowel Change 81) Daily Challenge #81 - Even or Odd 82) Daily Challenge #82 - English Beggars 83) Daily Challenge #83 - Deodorant Evaporator 84) Daily Challenge #84 - Third Angle of a Triangle 85) Daily Challenge #85 - Unwanted Dollars 86) Daily Challenge #86 - Wouldn't, not Would. 87) Daily Challenge #87 - Pony Express 88) Daily Challenge #88 - Recursive Ninjas 89) Daily Challenge #89 - Extract domain name from URL 90) Daily Challenge #90 - One Step at a Time 91) Daily Challenge #91 - Bananas 92) Daily Challenge #92 - Boggle Board 93) Daily Challenge #93 - Range Extraction 94) Daily Challenge #94 - Last Digit 95) Daily Challenge #95 - CamelCase Method 96) Daily Challenge #96 - Easter Egg Crush Test 97) Daily Challenge #97 - Greed is Good 98) Daily Challenge #98 - Make a Spiral 99) Daily Challenge #99 - Balance the Scales 100) Daily Challenge #100 - Round Up 101) Daily Challenge #101 - Parentheses Generator 102) Daily Challenge #102 - Pentabonacci 103) Daily Challenge #103 - Simple Symbols 104) Daily Challenge #104 - Matrixify 105) Daily Challenge #105 - High-Sum Matrix Drop 106) Daily Challenge #106 - Average Fuel Consumption 107) Daily Challenge #107 - Escape the Mines 108) Daily Challenge #108 - Find the Counterfeit Coin 109) Daily Challenge #109 - Decorate with Wallpaper 110) Daily Challenge #110 - Love VS. Friendship 111) Daily Challenge #111 - 99 Bottles of Beer 112) Daily Challenge #112 - Functions of Integers on the Cartesian Plane 113) Daily Challenge #113 - Iterative Rotation Cipher 114) Daily Challenge #114 - Speed Control 115) Daily Challenge #115 - Look and Say Sequence 116) Daily Challenge #116 - Shortest Knight Path 117) Daily Challenge #117 - MinMinMax 118) Daily Challenge #118 - Reversing a Process 119) Daily Challenge #119 - Adding Big Numbers

In today's challenge, you are asked to replace every letter with its position in the alphabet for a given string where 'a' = 1, 'b'= 2, etc.

For example:

alphabet_position("The sunset sets at twelve o' clock.") should return 20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11 as a string.


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

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

twitter logo DISCUSS (33)
markdown guide
 

JavaScript

My take at the challenge in JavaScript.

Source-Code

"use strict";

function lettersOnly(letterOrElse) {
  return letterOrElse.toUpperCase() !== letterOrElse.toLowerCase();
}

function toAlphabetPosition(letter) {
  return letter.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0) + 1;
}

function alphabet_position(input) {
  return Array
    .from(input)
    .filter(lettersOnly)
    .map(toAlphabetPosition)
    .join(" ");
}

const result = alphabet_position("The sunset sets at twelve o' clock.");
const expectations = "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11";

assert(result === expectations); // undefined (meaning OK)

Test it yourself

Available online here.

 
 
const alphaPosition = str => [...str]
  .filter(letter => letter.toLowerCase().charCodeAt(0) - 96 > 0)
  .map(letter => letter.toLowerCase().charCodeAt(0) - 96)
  .reduce((s, pos) => s += `${pos} `, '')
  .trim();

classic map filter reduce problem loved it.

 

x86_64 assembly (System V ABI, GNU assembler), as usual. Not really correct, since there will be an extra ' ' at the end which I was too lazy to remove, but it'll do.

alphabetic_position.S

    .global alphabetic_position

    .text
alphabetic_position:
    #using these registers to avoid sprintf breaking them
    push %rbx
    push %rbp

    mov %rdi, %rbx
    mov %rdi, %r12
    mov %rsi, %rbp

    xor %eax, %eax
    xor %edx, %edx
loop:
    mov (%rbp), %dl

    cmp $65, %dl # 'A'
    jl skip

    cmp $91, %dl # 'Z' + 1
    jl print

    cmp $97, %dl # 'a'
    jl skip

    cmp $123, %dl # 'z' + 1
    ja skip

printl:
    sub $32, %dl # 'a' -> 'A'
print:
    sub $64, %dl # 'A' -> 1

    push %rdx

    mov %rbx, %rdi
    mov $format, %rsi
    call sprintf

    add %rax, %rbx

    pop %rdx
skip:
    inc %rbp
    cmp $0, %dl
    jne loop

    mov %r12, %rax

    pop %rbp
    pop %rbx
    ret


    .section .rodata
format:
    .asciz "%d "

alphabetic_position.h:

char *alphabetic_position(char *dst, const char *src);

Edit: the function name now conforms to the specification, as well as with the "returns the string" requirement (by returning a copy of dst).

 
 

Rust:

pub fn alphabet_position(text: &str) -> String {
    text.to_lowercase()
        .chars()
        .filter(|c| c.is_alphabetic())
        .map(|char| (char as usize - 96).to_string())
        .collect::<Vec<String>>()
        .join(" ")
}

#[test]                                                                                        
fn test_alphabet_position() {                                                                  
    assert_eq!(                                                                                
        alphabet_position("The sunset sets at twelve o' clock."),                              
        String::from("20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11")
    );                                                                                         
}                                                                                              
 

this has shown me how similar rust syntax can be to JavaScript syntax wow

 

Python one liner to the rescue 🙂

print(*[ord(x.lower())-96 for x in input() if x.isalpha()])

 
import Data.Maybe (catMaybes)
import Data.List (find)
import Data.Functor (fmap)
import Data.Char (toLower) 

alpha = ['a'..'z']

isAlpha :: Char -> Bool
isAlpha = (`elem` alpha)

(>.<) :: (a -> b -> d) -> (c -> b) -> (a -> c -> d)
a >.< b = flip $ flip a . b

toNumber :: Char -> Maybe Int
toNumber = fmap snd . (flip find) alphaNum . ((==) >.< fst)
  where alphaNum = zip alpha [1..]

encodeMsg :: String -> String
encodeMsg = unwords . map show . catMaybes . map toNumber . filter isAlpha . map toLower

I wanted to try to write this function completely using point-free style. It led to me having to write that >.< operator, which you can see from the type definition exactly what it does. It was a good mental exercise in types for me, a Haskell beginner.

 

You don't need your filter isAlpha and isAlpha functions, since toNumber already returns None when the character isn't a letter, which chops off a nice bit of the solution!

You can also use findIndex from Data.List instead of find-with-zip (though that solution is cool! 😋

toNumber = (fmap (+1)) . (flip findIndex alpha) . (==)
 

In C++

#include <string>
#include <iostream>

void alphabet_position(std::string s) {
    for (int i = 0; i < s.size(); i++)
    {
        int pos = (int)((char)s[i] - 'a');
        pos = pos < 0 ? pos + ('a' - 'A') : pos;
        if (pos >= 0 && pos <= 'z' - 'a') {
            std::cout << pos+1 << " ";
        }
    }
}

int main (int argc, char *argv[])
{
    alphabet_position("<The quick brown fox jumps over the lazy dog!>");
    //print 20 8 5 17 21 9 3 11 2 18 15 23 14 6 15 24 10 21 13 16 19 15 22 5 18 20 8 5 12 1 26 25 4 15 7
    return 0;
}

Edited: there was a bug :D

 

JavaScript

const code = s => [...s].reduce((a, v) => v.match(/[a-z]{1}/i) 
                                          ? a+(v.toLowerCase().charCodeAt(0)-96)+' ' 
                                          : a
                        , '')
                        .trim();

And as an extra, the decoder:

const decode = s => String.fromCharCode(...s.split(' ').map(val=>parseInt(val) + 96));

Although the decoding process is not perfect, because all the spaces and symbols are lost during the coding process. For example, the sentence "The sunset sets at twelve o' clock" will be coded into:

"20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"

Which will be decoded into:

"thesunsetsetsattwelveoclock"

Link to live demo.

 

Haskell

Some function composition sorcery in Haskell.

import Data.Char (isLetter, toUpper, ord)

alphabet_position :: String -> String
alphabet_position = unwords . map (show . (flip (-)) 64 . ord . toUpper) . filter isLetter

Explanation

The . operator composes functions, so they will be applied from right to left.

  1. filter isLetter will remove all characters that are not letters from the string.
  2. map (show . (flip (-)) 64 . ord . toUpper) Transforms each character to its position in the alphabet.
    1. toUpper transforms the character to uppercase, so that we can substract 64 from it's code to know the position.
    2. ord maps a character to its ASCII code.
    3. (flip (-) 64) subtracts 64 from the character code. Since the code for 'A' is 65, this will give us the position in the alphabet starting at index 1. The way it works is it partially applies the second argument of the subtract operator to 64, i.e., this is equivalent to (\x -> x - 64) but fancier.
    4. show maps any type deriving from Show (Int in this case) to String.
  3. unwords joins a list of strings using space as a separator.
 

a bit late but here's the answer anyway... in PHP

function alphabet_position($text){
    $alphabet = range('a', 'z');     
    $strippedText = str_split(strtolower(preg_replace("/[^a-zA-Z]/", "", $text)));   
    $result = "";
    foreach($strippedText as $letter){
        $result .= array_search($letter, $alphabet)+1 . " ";   
    }
    return $result;
}
echo alphabet_position("The sunset sets at twelve o' clock.");
 

Perl solution:

#!/usr/bin/perl
use warnings;
use strict;

sub alphabet_position {
    join ' ', map ord() - 96, grep /[a-z]/, split //, lc shift
}

use Test::More tests => 1;

is alphabet_position("The sunset sets at twelve o' clock."),
    '20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11';

Reading from the right: shift gets the argument, lc lower-cases it, split using an empty regex splits it into characters, grep removes all non-letters, ord returns the ASCII ordinal number of each letter, 97 corresponds to a; map replaces the characters by the numbers, join connects the numbers back to a string.

See join, map, ord, grep, split, lc, shift.

 

Perl6:

sub alphabet-position(Str $text) {
    $text.lc().split("").comb(/<:Ll>/).map({.ord() - 96}).join(" ")
}

Or alternatively with the feed operator (and no type annotation, TIMTOWTDI):

sub alphabet-position($text) {
    $text 
    ==> lc()
    ==> split("")
    ==> comb(/<:Ll>/)
    ==> map({.ord() - 96})
    ==> join(" ")
}

alphabet-position("The sunset sets at twelve o' clock.").say
# 20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11

 

solved in rust made with tests first :)

pub fn alphabet_position(s: &str) -> String {
  s.to_lowercase()
    .chars()
    .filter(|x| x.is_alphabetic())
    .map(|x| -> u8 { x as u8 - 'a' as u8 + 1 })
    .map(|x| -> String { x.to_string() })
    .collect::<Vec<String>>()
    .join(" ")
}

#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn it_should_relace_the_a_with_1() {
    let replaced = alphabet_position("a");
    assert_eq!(replaced, "1");
  }

  #[test]
  fn it_should_relace_the_capital_a_with_1() {
    let replaced = alphabet_position("A");
    assert_eq!(replaced, "1");
  }

  #[test]
  fn it_should_ignore_non_characters() {
    let replaced = alphabet_position("'a a. 2");
    assert_eq!(replaced, "1 1");
  }

  #[test]
  fn it_should_relace_the_sentence() {
    let replaced = alphabet_position("The sunset sets at twelve o' clock.");
    assert_eq!(
      replaced,
      "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
    );
  }
}
 

In PHP using Laravel's Collection pipeline...

function alphabetPositions($string)
{
    return collect(str_split($string))
        ->map(function ($letter) {
            return collect(range('a', 'z'))->flip()->get(strtolower($letter));
        })
        ->filter()
        ->map(function ($key) {
            return $key + 1;
        })
        ->implode(' ');
}

echo alphabetPositions("The sunset sets at twelve o' clock.");

Will be cleaner when PHP gets shorthand arrow functions, which I believe are coming in 7.4 😍 ...

function alphabetPositions($string)
{
    return collect(str_split($string))
        ->map(fn($letter) => collect(range('a', 'z'))->flip()->get(strtolower($letter)))
        ->filter()
        ->map(fn($key) => $key + 1)
        ->implode(' ');
}

echo alphabetPositions("The sunset sets at twelve o' clock.");
 

Lua, just as a series of string operations:

local function solution(text)
    return text:lower()
        :gsub("%A+", "")
        :gsub("%a", function(n) return " " .. 1 + n:byte() - string.byte("a") end)
        :sub(2)
end

Lua, written with a loop and so a bit less wasteful:

local function solution(text)
    local ns = {}
    for a in text:gmatch("%a") do
        table.insert(ns, 1 + a:lower():byte() - string.byte("a"))
    end
    return table.concat(ns, " ")
end
 

A JS one-liner

alphaPosition = s => [...s.toLowerCase().replace(/[^a-z]/g, '')].map(c => c.charCodeAt(0) + 1 - 'a'.charCodeAt(0)).join(' ');

Output:

> alphaPosition("The sunset sets at twelve o' clock.")
< "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
 

JavaScript

let position = (str) => {
    const upper = str.trim().toUpperCase().split('');
    let arr = [];
    upper.map(l => (/^[a-z]+$/i.test(l)) && arr.push(l.charCodeAt(0)-64).toString())
    return arr.join(" ");
}

position("The sunset sets at twelve o' clock.");
 

ruby <3

def alphabet_position(s)
  pos = (?a..?z |> zip 1..26 |> to_h)
  s |> downcase |> scan /[a-z]/ |> map &pos |> join ' '
end
 

My take on this challenge, with Javascript

const encode = str => [...str.toLowerCase().replace(/[^a-z]/g, '')]
        .map(ch => ch.charCodeAt() - 96)
        .join(' ');

 
 

"One-liner" (kind of) Ruby:

def alphabet_position(str)
  str.downcase.split('').select { |c| c =~ /[a-z]/ }.map { |c| c.ord - 96 }.join(' ')
end
 
def alphabet_position(str)
  str.downcase.gsub(/[^a-z]/, '').split('').map{|c| c.ord - 96}.join(' ')
end
 

C#

public static string AlphabetPosition(string text)
{
   return string.Join(" ", text
    .ToLower()
    .Where(c => char.IsLetter(c))
    .Select(c => (c - 'a') + 1)
    .ToList());
}
 

A tiny python solutiuon:

def alphabet_position(text):
    converted = [str(ord(c) - ord('a') + 1) for c in text.lower() if c >= 'a']
    return " ".join(converted)
 

One line Javascript

const alphaPosition = str => [...str]
  .filter(letter => /[a-zA-Z]/.test(letter))
  .map(letter => letter.toLowerCase().charCodeAt(0) - 96)
  .join(' ')
 
 

Python :

lambda s : ' '.join([str(ord(c)-ord('a')+1) for c in s.lower() if re.search('[a-z]',c)])
 
function alphabetPosition(text) {
  return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, str => str.charCodeAt() - 64 + ' ').trim();
}
Classic DEV Post from May 19

Don't let that huge codebase scare you! Tips and tools to make sense of other people's code

Parsing through a large, existing codebase can be challenging if you're new to a project. I'll share a few tips and tools for how you can make sense of other people's code without going crazy.

dev.to staff profile image
The hardworking team behind dev.to ❤️

Make better choices about your code and your career.

Create Your Account. 100% Free Forever.