## DEV Community is a community of 751,589 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

# Daily Challenge #110 - Love VS. Friendship

If　`a = 1, b = 2, c = 3 ... z = 26`

Then `l + o + v + e = 54`

and `f + r + i + e + n + d + s + h + i + p = 108`

So friendship is twice as strong as love :-)

Write a function to find the "strength" of each of these values.

Test cases:
```wordsToMarks(attitude) wordsToMarks(friends) wordsToMarks(family) wordsToMarks(selflessness) wordsToMarks(knowledge)```

Good luck!

This challenge comes from J or nor J 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!

## Discussion (28) A bit like @nicolas Hervé, using the `reduce` method:

``````f=a=>[...a].reduce((t,l)=>t+l.charCodeAt``-96,0)
``````
• `[...a]` transforms the string to an array with every character (`["l", "o", "v", "e"]`)
• The `reduce` methods will loop through every character, get its charCode, subtract `96` to it (the charCode associated with `"a"` + 1), and sum everything kesprit

Thanks to @ynndvn for showing me `reduce` method, it exist too in Swift language and it's awesome !!!

This is my solution in Swift :

``````func wordsToMarks(word: String) -> Int {
return word.compactMap { \$0 }.reduce(0) {
\$0 + Int(\$1.asciiValue ?? 0) - 96
}
}

wordsToMarks(word:"attitude")
wordsToMarks(word:"friends")
wordsToMarks(word:"family")
wordsToMarks(word:"selflessness")
wordsToMarks(word:"knowledge")
`````` Michael Kohl • Edited on

Why the `compactMap`, you are mapping each letter to itself, works fine without that too.

Also when I tried your solution with the input string "love🐈" it returned -42 since the way you handle the `Optional` results in non-ASCII characters having a value of -96. The following version simply ignores such characters instead:

``````func wordsToMarks(word: String) -> Int {
return word.reduce(0) {
\$0 + Int(\$1.asciiValue.map { \$0 - 96 } ?? 0)
}
}
`````` kesprit

Oh nice! That's better !

I forgot `String` are a table of `Character` so you right `compactMap` is useless.
I have totally ignored emojis because the challenger treat only letter `a` to `z`

So thank you for your feedback, your optimisation is truly better 👌 Michael Kohl

I have totally ignored emojis because the challenger treat only letter a to z

True, but you did add some code to deal with the case were a character may not have an `asciiValue`, I just offered an alternative to that :-) Donald Feury • Edited on

I started picking up ruby for rails, so here is my shining gem.

Try it out here

word.rb

``````class Word
@@alphabet = ('a'..'z').to_a

def self.to_mark(word)
word.chars.sum { |char| @@alphabet.index(char.downcase) + 1 }
end
end
``````

word_test.rb

``````require 'minitest/autorun'
require_relative 'word'

class TestWord < Minitest::Test
def setup
@cases = [
{ input: 'love', expected: 54 },
{ input: 'friendship', expected: 108 },
{ input: 'attitude', expected: 100 },
{ input: 'friends', expected: 75 },
{ input: 'family', expected: 66 },
{ input: 'selflessness', expected: 154 },
{ input: 'knowledge', expected: 96 }
]
end

def test_to_mark
@cases.each { |test| assert_equal test[:expected], Word.to_mark(test[:input]) }
end
end
`````` Michael Kohl

Just a friendly tip: `alphabet` really shouldn't be a class variable `@@`, they are very seldom what you want in Ruby:

railstips.org/blog/archives/2006/1...

In this specific case a constant would be the most common:

``````ALPHABET = ('a'..'z').to_a
`````` Yechiel Kalmenson
``````def wordsToMarks(word)
alphabet = ("a".."z").to_a
mark = 0
word.each_char do |char|
mark += alphabet.index(char.downcase) + 1
end
mark
end
`````` Yechiel Kalmenson

Well, my first attempt had me iterating calling `.index` on `("a".."z")` only to find out that you can't call index on a range, so in trying to work around that I realized I could just convert the range into an array... :) Michael Kohl • Edited on

Ruby:

``````def words_to_marks(word)
word.chars.sum { |c| c.ord - 96 }
end

``````

For fun a second version that builds a lookup table with an endless range (introduced in Ruby 2.6):

``````ALPHABET = ('a'..'z').zip(1..).to_h

def words_to_marks(word)
word.chars.sum { |c| ALPHABET.fetch(c, 0) }
end
`````` peter279k

Here is the simple solution with Python:

``````def words_to_marks(s):
alphabet = {
'a': 1,
'b': 2,
'c': 3,
'd': 4,
'e': 5,
'f': 6,
'g': 7,
'h': 8,
'i': 9,
'j': 10,
'k': 11,
'l': 12,
'm': 13,
'n': 14,
'o': 15,
'p': 16,
'q': 17,
'r': 18,
's': 19,
't': 20,
'u': 21,
'v': 22,
'w': 23,
'x': 24,
'y': 25,
'z': 26,
}

sum_length = 0
for char in s:
sum_length += alphabet[char]

return sum_length
`````` Karin

A little solution for Ruby :) this was fun!

``````def wordsToMarks(word)
strength = 0
alphabet = ('a'..'z').to_a
word.split('').each do |i|
strength = strength + (alphabet.index(i) + 1)
end
return strength
end
`````` Jon Bristow
``````words_to_marks("",0).
words_to_marks(S,Mark) :-
string_codes(S,SC),
length(SC, SCL),
sum_list(SC,SCS),
Mark is SCS - SCL * 96.
``````
``````?- words_to_marks(“love”, V).
% V = 54

?- words_to_marks(“declarative”, V).
% V = 100
`````` Michael Kohl

Nice to see some Prolog :-) Ed Reeseg • Edited on
``````#include <stdio.h>

int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./strength string\n");
return 1;
}
int sum = 0;
char *c = argv;
while(*c != '\0')
{
if (*c < 'a' || *c > 'z')
{
printf("Invalid argument\n");
return 1;
}
sum += *c - 'a' + 1;
c++;
}
printf("%i\n", sum);
return 0;
}
`````` Lloric Mayuga Garcia • Edited on

In PHP

``````
\$alpha = function (string \$string) {
\$al = array_flip(range('a', 'z'));

\$points = 0;
foreach (str_split(\$string) as \$s) {
\$points += \$al[\$s] + 1;
}
return \$points;
};

echo \$alpha('friendship');
``````

EDIT:

``````array_map(function (string \$string) {
\$al = array_flip(range('a', 'z'));

\$points = 0;
foreach (str_split(\$string) as \$s) {
\$points += \$al[\$s] + 1;
}
echo "\$string: \$points<br>";
}, ['attitude', 'friends', 'family', 'selflessness', 'knowledge']);

attitude: 100
friends: 75
family: 66
selflessness: 154
knowledge: 96
`````` Michael Kohl • Edited on

The prelude defines `subtract`, so you don't need `flip` here:

``````wordsToMarks = sum . map (subtract 96 . ord)
``````

Another relatively common workaround is to use a right-section that adds a negative number, i.e.

``````wordsToMarks = sum . map ((+(-96)) . ord)
`````` Michael Kohl

Since `-` is both subtraction and unary minus one can’t use a right-section like `(-1)`, but considering that subtracting is the same as adding a negative number the slightly obscure form makes sense. I’d still use `subtract` though. Tallie

My solution to the challenge using map and reduce in Python. If anyone has any suggestions on how to improve it, I would love to hear! :)

``````from functools import reduce
def wordsToMarks(word):
print(reduce((lambda x,y: x+y), map((lambda x: ord(x) - 96), list(word))))
`````` Vitaliy Kononenko

Here is my fun solution using Kotlin:

``````fun wordsToMarks(word: String) = word.toCharArray()
.map { it + 1 - 'a' }
.sum()
`````` Zohar Peled

c#, one liner using linq, ignoring non-letters chars:

``````int WordsToMarks(string word)
{
return word.Where(c => char.IsLetter(c)).Sum(c => char.ToUpperInvariant(c) - 64);
}
`````` David Kanekanian • Edited on

My Python Algorithm:

``````words_to_marks = lambda words: sum(
map(ord, words.lower()),
-96 * len(words))
``````