Given a string of words you need to find the highest scoring word

CodeWars Python Solutions


Highest Scoring Word

Given a string of words, you need to find the highest scoring word.

Each letter of a word scores points according to its position in the alphabet: a = 1, b = 2, c = 3 etc.

You need to return the highest scoring word as a string.

If two words score the same, return the word that appears earliest in the original string.

All letters will be lowercase and all inputs will be valid.


Given Code


Solution 1

def high(x):
    alp = "abcdefghijklmnopqrstuvwxyz"
    counter = [sum([alp.find(i) + 1 for i in w]) for w in x.split()]
    return x.split()[counter.index(max(counter))]

Solution 2

def high(x):
    return max(x.split(), key=lambda k: sum(ord(c) - 96 for c in k))

See on CodeWars.com

I am trying to solve CodeWars challenges but I have a problem with this one:

«Given a string of words, you need to find the highest scoring word.
Each letter of a word scores points according to its position in the alphabet:

 a = 1, b = 2, c = 3 etc.

You need to return the highest scoring word as a string.
If two words score the same, return the word that appears earliest in the original string.
All letters will be lowercase and all inputs will be valid.»

My code passed 104 cases but got wrong on 1 case.
The wrong answer test case is

'what time are we climbing up the volcano' 

According to codewars — Expected: ‘volcano’, instead got: ‘climbing’

Any ideas?

link of the problem — https://www.codewars.com/kata/57eb8fcdf670e99d9b000272/train/javascript

 function high(x){
  let result = '', value =0, counterValue = 0; 

  let splittedArray = x.split(' ');

  splittedArray.map(splitItem => {
    counterValue = 0;

    let splitItemArray = splitItem.split('');

    splitItemArray.map(splitChar => { 
      counterValue += splitChar.charCodeAt();
    })

    if(counterValue>value){
      result = splitItem;
      value = counterValue;
    }
  });
  return result;
}

Michael Nelles's user avatar

asked Mar 31, 2020 at 17:42

Mustafizur Rahman Choudhury's user avatar

3

function high(x) {
  const words = x.split(' ');
  const alphabetMap = {};
  for (let i='a'.charCodeAt(), j = 1; i <= 'z'.charCodeAt(); i++, j++) {
    alphabetMap[i] = j;
  }
  let highestScoringWord = { word: '', score: 0 };
  words.forEach(w => {
    const chars = w.split('');
    const sumOfChars = chars.reduce((count, char) => count + alphabetMap[char.charCodeAt()], 0);
    if (sumOfChars > highestScoringWord.score) {
      highestScoringWord = { word: w, score: sumOfChars };
    }
  });

  return highestScoringWord.word;
}

console.log(high('what time are we climbing up the volcano')) // volcano ;)

answered Mar 31, 2020 at 18:08

Vazgen's user avatar

5

You can use reduce and object to keep track of highest count and respective word

function high(x){
  let mapper = [...`abcdefghijklmnopqurstuvwxyz`].reduce((op,inp,index)=>{
    op[inp] = index+1
    return op
  },{})
  return x.split(' ').reduce((op,inp)=>{
    let currentCount = 0;
    [...inp].forEach(v=>{
      currentCount += mapper[v]
    })
    if(currentCount > op.maxCount){
      op.maxCount = currentCount
      op.word = inp
    }
    return op
  }, {maxCount:0, word:''}).word
}

console.log(high('what time are we climbing up the volcano'), 'volcano'))

answered Mar 31, 2020 at 17:55

Code Maniac's user avatar

Code ManiacCode Maniac

36.9k5 gold badges38 silver badges60 bronze badges

5

the solution is to use an array of the alphabet and indexing the character position in it,

let al = `abcdefghijklmnopqrstuvwxyz`.split('')


   function high(x){
     let words = x.split(" ");
     let out = words.map(word => {
     let score = 0;
     let letters = word.split("");
     letters.map(c => {
      score += al.indexOf(c);
     })
     return [word, score];
    });

    out = out.sort((a,b) => { 
      if(a[1] > b[1]) return -1;
      else if(a[1] < b[1]) return 1; 
      else return 0;  });

return out[0][0];
}

answered Mar 31, 2020 at 18:13

Adarsh Hegde's user avatar

Adarsh HegdeAdarsh Hegde

6232 gold badges7 silver badges19 bronze badges

2

I’m confused by your counterValue += splitChar.charCodeAt(); line. I don’t understand how splitChar.charCodeAt() translates into 1-26 aka a letters position in the alphabet. «Each letter of a word scores points according to its position in the alphabet»

I was able to able to make your code work by doing two things:

  1. Add a map to store the value of each letter in the alphabet. I’m sure this can be done many ways but this was my approach:
let letterValues = { 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 };
  1. And then use this in counterValue += splitChar.charCodeAt(); as counterValue += letterValues[letter];

answered Mar 31, 2020 at 18:16

Jason Lydon's user avatar

Jason LydonJason Lydon

7,0041 gold badge34 silver badges43 bronze badges

0

Idea:

  • Store the score values in a table for easy lookup
  • split sentences into words by non-alphabetic characters
  • get each word’s score by first calculating the individual characters’ scores and then summing them together (using reduce).
  • Don’t forget to sort by original position if scores are the same, do it by keeping track of the original position.

Demo: https://jsfiddle.net/9xkfqh1m/

const ScoreTable = {
  "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
};

// non-ascii letters = 0
function CharScore(char) {
  const lowerCaseChar = char.toLowerCase();
  return lowerCaseChar in ScoreTable ? ScoreTable[lowerCaseChar] : 0;
}

function WordScore(word) {
  return word.split("").reduce((score, char) => {
    return score + CharScore(char);
  }, 0);
}

function SplitOnNonAlphabeticCharacters(str) {
  return str.split(/[^a-zA-Z]+/gm);
}

function high(str){
  const scoreObjects = SplitOnNonAlphabeticCharacters(str)        // split into words
  .map((word, index) => {                                         // map our words into an object with its score and original position
    return {
      text: word,
      score: WordScore(word),
      originalPosition: index
    };
  }).sort((word1, word2) => {                                        // sort
    return word2.score - word1.score                                 // highest score first
                ||  word1.originalPosition - word2.originalPosition; // if score same, earliest original position in string
  });

  return scoreObjects.length > 0 ? scoreObjects[0].text : null;   // return word by the highest score (or earliest original position), or null
}

answered Mar 31, 2020 at 18:34

Asher Garland's user avatar

Asher GarlandAsher Garland

4,8635 gold badges27 silver badges29 bronze badges

0

The charCodeAt() method returns an integer between 0 and 65535 representing the UTF-16 code unit at the given index.

Basically you need to convert it to an uppercase alphabet and subtract the value of the charCodeAt by 64 which will give you the position of the string in the alphabet.

Check this one out:

function high(x) {
    let splittedArray = x.split(' ');
    let splitChar = splittedArray.map(el => el.split(''));
    let charValue = splitChar.map(el => {
        let counter = 0;
        el.map(element => counter += element.toUpperCase().charCodeAt() - 64);
        return counter;
    });
    let largest = 0;
    let largestIndex;
    for (let i = 0; i < charValue.length; i++) {
        if (charValue[i] > largest) {
            largest = charValue[i];
            largestIndex = i;
        }
    }
    return splittedArray[largestIndex];
}

answered Mar 31, 2020 at 18:51

Shahriar Shojib's user avatar

2

I made a mistake by not counting letters position in the alphabet. If I subtract 96 from ASCII value then it will calculate a as 1, b as 2......

So the solution is given below

 function high(x){
  let result = '', value =0, counterValue = 0; 

  let splittedArray = x.split(' ');

  splittedArray.map(splitItem => {
    counterValue = 0;

    let splitItemArray = splitItem.split('');

    splitItemArray.map(splitChar => { 
      counterValue += splitChar.charCodeAt()-96; // if I subtract 96 then it will calculate a as 1, b as 2......
    })

    if(counterValue>value){
      result = splitItem;
      value = counterValue;
    }
  });
  return result;
}

answered Mar 31, 2020 at 19:03

Mustafizur Rahman Choudhury's user avatar

function high(x){
const str = x.split(' ');
const result1 = [];
const result = str.reduce((_, dig) => {
  let c = 0;
  for (let j = 0; j < dig.length; j++) {
    c = c + (dig.charCodeAt(j) - 96);
  }
  result1.push(c);
}, 0);
return str[result1.indexOf(result1.slice().sort((a, b) => b - a)[0])];
}

answered Jun 23, 2021 at 18:28

KVR's user avatar

1

Thought I’d post since I solved it, even though the post is pretty old. Anyway this was solved from pure javascript.

//This main function loops thru each sum from the helper function and returns the position of the highest scoring word

function highestScoringWord(sentence) {
let arr = []
let sentenceSplit = sentence.split(' ')
for(i=0; i<sentenceSplit.length; i++) {
arr.push(scoringWord(sentenceSplit[i]))
}
let max = arr[0]
for(x=0; x<arr.length; x++) {
    if(arr[x] > max) {
        max = arr[x]
    }   
}

for(p=0; p<arr.length; p++) {
    if(max === arr[p]) {
        return sentenceSplit[p]
    }
}

}

//Helper function that takes a word, splits it, and sums up the numbers that each letter is worth.

function scoringWord(word) {
 let wordSplit = word.split('')
 let alphabet = 'abcdefghijklmnopqrstuvwxyz'
 let sum = 0
 for(j=0; j<word.length; j++) {
     sum+=alphabet.indexOf(word[j])
 }
 return sum
}

answered Nov 15, 2021 at 0:50

Josh's user avatar

JoshJosh

311 silver badge4 bronze badges

function high(x){
const ScoreTable = [«0», «a», «b», «c», «d», «e», «f», «g», «h», «i», «j», «k»,»l», «m», «n», «o», «p», «q», «r», «s», «t», «u», «v», «w»,»x», «y», «z»];

return x.split(" ").map(word => {
    let code = 0
    word.split("").map(letter => code += ScoreTable.indexOf(letter))
    return [word, code]
}).sort((a,b) => b[1] - a[1])[0][0]

}

answered Aug 29, 2022 at 22:23

Dmitry Butakov's user avatar

1

Welcome to code review, good job as your first program I suppose.

Style

Docstrings: Python documentation strings (or docstrings) provide a convenient way of associating documentation with Python modules, functions, classes, and methods. An object’s docstring is defined by including a string constant as the first statement in the object’s definition.

def word_value(input_word):
def high(x):

You should include a docstring with your functions indicating what they do specially the names are pretty ambiguous …

def get_word_value(word):
    """Return word letter score."""

def get_highest_scoring_word(word_list):
    """Return highest scoring word."""

Blank lines: I suggest you check PEP0008 https://www.python.org/dev/peps/pep-0008/ the official Python style guide and regarding blank lines, use blank lines sparingly to separate logical sections inside a function (too many blank lines in your high function)

word_values = []
for word in word_list:
    word_values.append(word_value(word))

max_value = max(word_values)
index_of_max = word_values.index(max_value)

return word_list[index_of_max]

Code

First function

can be shortened in the following way:

import string
values = dict(zip(string.ascii_lowercase, range(1, 27)))

def get_value(word):
    """Return word letter score."""
    return sum(values[letter] for letter in word)

Second function:

word_list = x.split(" ")

split() has a default value of » » so no need to specify

word_list = x.split()

does the same functionality

Descriptive names:

word_list is extremely confusing, because word_list is not a list so I suggest changing the name to word_sequence

Comprehension syntax:

word_values = []
for word in word_list:
    word_values.append(word_value(word))

this can be enclosed in a comprehension syntax (it’s more efficient and shorter)

word_values = [word_value(word) for word in word_sequence]

Code might look like:

import string
values = dict(zip(string.ascii_lowercase, range(1, 27)))


def get_value(word):
    """Return word letter score."""
    return sum(values[letter] for letter in word)


def get_highest(word_sequence):
    """
    Return word with the highest score assuming word_sequence a 
    string of words separated by space.
    """
    return max(word_sequence.split(), key=get_value)


if __name__ == '__main__':
    words = 'abc def ggg'
    print(get_highest(words))

The problem today is quite simple. It concerns arrays, strings, and character encoding within JavaScript. In addition to a pinch of elementary mathematics, specifically the sum of numbers. But let’s start from the beginning, that is, from the problem text.

The Problem: Highest Scoring Word

link to the kata

sentences, beautiful light, soft colour scheme, numbers, dream

Given a string of words, you need to find the highest scoring word.

Each letter of a word scores points according to its position in the alphabet: a = 1, b = 2, c = 3 etc.

For example, the score of abad is 8 (1 + 2 + 1 + 4).

You need to return the highest scoring word as a string.

If two words score the same, return the word that appears earliest in the original string.

All letters will be lowercase and all inputs will be valid.

My Solution

sentences, beautiful light, soft colour scheme, numbers, dream

The problem can be broken down into some simpler problems.

  1. divide the sentence into words
  2. calculate the value of each word
  3. find the highest value
  4. return the first word with the highest value

To transform a sentence into an array of words, I can use the String.split() method with the argument ` `.

const words = "hello world";
const listWords = words.split(" ");

console.log(listWords); // ["hello", "world"]

To calculate the value of each word, I can use two methods. I can create a dictionary containing the letters of the alphabet and use it to assign a value to each word:

const charToScore = { 'a': 1, 'b': 2, 'c': 3, ...}

But I think that this is not the best way. To solve this problem, I can use the String.charCodeAt() method to get the ASCII code value of each character. This way, I can calculate the value of each word simply by summing the values of each character.

const word = "hello";
const value = [...word].reduce((a, c) => a + c.charCodeAt(0), 0);

console.log(value); // 532

There is however a problem: the value of a is 97, that of b is 98 and so on. To solve this problem I have to subtract 96 from each value. In this way, the value of a becomes 1, that of b becomes 2 and so on.

const word = "hello";
const value = [...word].reduce((a, c) => a + (c.charCodeAt(0) - 96), 0);

console.log(value); // 52

The next step is to find the highest value among those assigned to words. I can use the Math.max() method to find the highest value among those contained in an array.

const values = [1, 2, 3, 4, 5];
const maxValue = Math.max(...values);

console.log(maxValue); // 5

But we need the word corresponding to the value, not the value itself. To find the word corresponding to the highest value, I can use the Array.indexOf() method.

const values = [1, 2, 3, 4, 5];
const maxValue = Math.max(...values);
const indexMaxValue = values.indexOf(maxValue);

console.log(indexMaxValue); // 4

By combining the various pieces, I can finally write my solution.

const getValues = (w) =>
  w
    .split(" ")
    .map((w) => [...w].reduce((a, c) => a + (c.charCodeAt(0) - 96), 0));
const indexMax = (x) => x.indexOf(Math.max(...x));

const high = (x) => {
  const listWords = x.split(" ");
  const listValue = getValues(x);
  const maxValue = indexMax(listValue);

  return listWords[maxValue];
};

A Better Solution

sentences, beautiful light, soft colour scheme, numbers, dream

But I can solve the same problem with a different approach. Instead of assigning a value to each word, looking for the maximum value and then looking for which word corresponds to the value, I can simply sort the words based on the value they have. In this way, the word with the highest value will be the first in the list.

To do this, I use the Array.sort() method.

const value = (w) => [...w].reduce((a, c) => a + (c.charCodeAt(0) - 96), 0);

const high = (x) => {
  const order = x.split(" ").sort((a, b) => value(b) - value(a));
  return order[0];
};

I can turn everything into an arrow function. This allows us to solve the problem with just two lines of JavaScript code.

const value = (w) => [...w].reduce((a, c) => a + (c.charCodeAt(0) - 96), 0);
const high = (x) => x.split(" ").sort((a, b) => value(b) - value(a))[0];

A more extreme solution combines both lines in a single function.

const high = (x) =>
  x
    .split(" ")
    .sort(
      (a, b) =>
        [...b].reduce((z, c) => z + (c.charCodeAt(0) - 96), 0) -
        [...a].reduce((z, c) => z + (c.charCodeAt(0) - 96), 0)
    )[0];

Instructions

Given a string of words, you need to find the highest scoring word.

Each letter of a word scores points according to it’s position in the alphabet: a = 1, b = 2, c = 3 etc.

You need to return the highest scoring word as a string.

If two words score the same, return the word that appears earliest in the original string.

All letters will be lowercase and all inputs will be valid.


My Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Arrays;
import java.util.Comparator;

public class HighScoreingWord {
public static String high(String s) {
return Arrays.stream(s.split(" "))
.max(Comparator.comparing(HighScoreingWord::scoreOfWord)).get();
}

public static int scoreOfWord(String word) {
return word.chars().sum() - word.length() * 96;
}
}

Better Solution

1
2
3
4
5
6
7
8
9
10
11
import java.util.Arrays;
import java.util.Comparator;

public class HighScoreingWordSolution {
public static String high(String s) {
return Arrays.stream(s.split(" "))
.max(Comparator.comparingInt(word -> word.chars().map(charr -> charr - 96).sum()))
.get();
}

}

Feeling

아직 제대로 람다를 공부해서 쓰는게 아니다 보니 Comparator를 모르고 있었는데 이번 문제를 통해서 알게되어 좋았다!

지금 읽는 책 다 읽고 나면 바로 자바 8 인 액션 책을 읽어봐야겠다.

Понравилась статья? Поделить с друзьями:
  • Give you my word idiom
  • Give you my word as you take it and run
  • Give word get sentence
  • Give word from typed meanings
  • Give up similar word