# Daily Challenge #110 - Love VS. Friendship

### dev.to staff twitter logo Nov 7 '19・1 min read

Daily Challenge (246 Part Series)

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!

DISCUSS (27)
Discussion 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

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
``````

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
``````

Ah okay gotcha, thank ya for the tip!

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")
``````

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)
}
}
``````

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 👌

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 :-)

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

("a".."z").to_a is nifty!

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... :)

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
``````

``````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
``````

Nice to see some Prolog :-)

``````#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;
}
``````

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
``````

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))))
``````

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)
``````

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.

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
``````

Here is my fun solution using Kotlin:

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

Classic DEV Post from Aug 4 '19

## You're not worth hiring unless...  