Reputation: 13
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;
}
Upvotes: 1
Views: 9596
Reputation: 1
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]
}
Upvotes: 0
Reputation: 31
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
}
Upvotes: 0
Reputation: 1
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])];
}
Upvotes: 0
Reputation: 13
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;
}
Upvotes: 0
Reputation: 927
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];
}
Upvotes: 0
Reputation: 5001
Idea:
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
}
Upvotes: 0
Reputation: 7180
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:
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 };
counterValue += splitChar.charCodeAt();
as counterValue += letterValues[letter];
Upvotes: 0
Reputation: 631
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];
}
Upvotes: 1
Reputation: 59
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 ;)
Upvotes: 1
Reputation: 37755
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'))
Upvotes: 1