Reputation: 43
For example: "Today, is the greatest day ever!" should return greatest because it has 2 e's (and 2 t's) and it comes before ever which also has 2 e's. If there are no words with repeating letters return -1. Words will be separated by spaces. Input:"Hello Apple Pie" Output should be:"Hello" Do not understand what is wrong with my code, also if you think there is a simpler and shorter way to solve I would love to hear it. Thanks in advance for the help.
function LetterCountI(str) {
let unique=[... new Set(str)]
if(unique==str){
return -1}
let arr= str.split(" ")
let array=arr.map(item=>{
let temparr=item.split("")
return temparr.reduce((acc,curr)=>{
acc[curr]=acc[curr]? acc[curr]+1:1
if(acc[curr]>acc.max){
acc.max=acc[curr]}
return acc},{max:1, word:item})})
let amount=1
let largest=""
for(let item of arr){
if( item.max>amount){
amount=item.max
largest=item.word
}
}
return largest
}
Upvotes: 0
Views: 1003
Reputation: 50797
My initial approach would involve separating out a maxBy
function that accepts a function extracting a comparison number from an input value and returns a function from a list of values to the largest one of those.
Then we could write letterCount
to count the occurrences of various letters in a string, and wrap that up with a function, maxLetterCount
that calculates the maximum letter count for a string, using Math .max
on the values from letterCount
, and write our main function to split your initial string into words and call maxBy
using maxLetterCount
against the list of words. It could look like this:
// DO NOT USE -- Doesn't meet all requirements!
const maxBy = (fn) => (xs) => xs .reduce (
({m, r}, x) => {const v = fn(x); return v > m ? {m: v, r: x} : {m, r}},
{m: -Infinity}
) .r
const letterCount = ([...cs]) =>
cs .reduce ((a, c) => {a [c] = (a [c] || 0) + 1; return a}, {})
const maxLetterCount = (cs) =>
Math .max (... Object .values (letterCount (cs)))
const letterCountI = (s) =>
maxBy (maxLetterCount) (s .split (/\s+/))
console .log (letterCountI ("Today, is the greatest day ever!"))
console .log (letterCountI ("Hello Apple Pie"))
But there is a problem with this approach. It doesn't take into account your requirement that if there are no duplicated letters, we must return -1
. Right now, letterCountI ("Today is the day")
will return "Today"
.
One fix for this problem might involve pairing the words with their max letter counts, filtering these pairs to only those which have multiply-occurring letters, then use maxBy
again on the pairs, and finally pull the word out of the winning pair. To handle the -1
case we could insert a dummy pair into the filtered list with -1
for the word and -Infinity
for the letter count. If the list is otherwise empty, then we will choose this one.
And doing this might lead us to add some defaulting behavior to maximumBy
, which right now is limited to numbers, but ideally should work with anything we can compare using <
. If we defaulted our lower bound of -Infinity
, but allowing override, and paired that with a default value for an empty list, then we could probably do the above in a fairly simple way.1
But that feels a bit overcomplicated. Perhaps a simpler approach would be to simply perform the code as above, then test if the resulting word has any repeated letter. While we could track this through the function, I think the simplest version would be to call letterCount
again on it. So this is how I would probably choose to write this function:
const maxBy = (fn) => (xs) => xs .reduce (
({m, r}, x) => {const v = fn(x); return v > m ? {m: v, r: x} : {m, r}},
{m: -Infinity}
) .r
const letterCount = ([...cs]) =>
cs .reduce ((a, c) => {a [c] = (a [c] || 0) + 1; return a}, {})
const maxLetterCount = (cs) =>
Math .max (... Object .values (letterCount (cs)))
const letterCountI = (s, target = maxBy (maxLetterCount) (s .split (/\s+/))) =>
maxLetterCount (target) > 1 ? target : -1
console .log (letterCountI ("Today, is the greatest day ever!"))
console .log (letterCountI ("Hello Apple Pie"))
console .log (letterCountI ("Today, is the day!"))
1 That might look like this (untested) version:
const maximumBy = (fn, {dfltVal = '', lowBound = -Infinity} = {}) => (xs) => xs .reduce (
({m, r}, x) => {const v = fn(x); return v > m ? {m: v, r: x} : {m, r}},
{m: lowBound, r: dfltVal}
) .r
Upvotes: 1
Reputation: 13377
Staying with the OP's reduce
based approach one would provide a single function which incorporates two specific nested reduce
tasks responsible for 1) aggregating the word specific statistics of a sentence and 2) the letter specific statistics for each word.
This approach also ensures the result of ''
(suggested) or -1
(the OP'S requirement) in case there are only words of unique (non repeating) letters/characters.
function getFirstOccurringWordOfMaximumSameCharacterCount(value) {
function aggregateCharCountData(wordStats, char, idx, arr) {
const { charStats } = wordStats;
// aggregate character specific array.
(charStats[char] ??= []).push(char);
if (idx >= (arr.length - 1)) {
// console.log({ charStats });
// aggregate maximum character count data
// at the end of the last character reduce step.
const maxCharList = Object
.values(charStats)
.sort((aCharList, bCharList) =>
bCharList.length - aCharList.length
)[0];
wordStats.maxCharCount = maxCharList.length;
wordStats.maxCountChar = maxCharList[0];
}
return wordStats;
}
function aggregateWordSpecificCharCountData(collector, word, idx, arr) {
const { statistics } = collector;
statistics.push(
word
.split('')
.reduce(aggregateCharCountData, { word, charStats: {} })
);
if (idx >= (arr.length - 1)) {
// find the first occurring word of maximum same character count
// at the end of the last word reduce step.
const wordStats = statistics
.sort((aWordStats, bWordStats) =>
bWordStats.maxCharCount - aWordStats.maxCharCount
)[0];
// console.log({ statistics });
collector.result = (wordStats.maxCharCount >= 2)
? wordStats.word
: ''; // : -1;
}
return collector;
}
const {
// statistics,
result,
} = String(value)
.split(/\s+/)
.reduce(aggregateWordSpecificCharCountData, {
statistics: [],
result: '',
});
// console.log({ statistics });
return result;
}
console.log([
'Today is the day.', // ''
'Today, is the greatest day ever!', // 'greatest'
'Hello Apple Pie', // 'Hello'
'She sells seashells by the seashore' // 'seashells'
].map(getFirstOccurringWordOfMaximumSameCharacterCount));
.as-console-wrapper { min-height: 100%!important; top: 0; }
Upvotes: -1
Reputation: 62676
Start with the simpler problem of getting the frequency of each letter in a word...
// given "sassy", will return { s:3, a:1, y:1 }
function letterFrequency(word) {
return word.split('').reduce((acc, letter) => {
if (!acc[letter]) acc[letter] = 0;
acc[letter]++;
return acc;
}, {});
}
A simple problem to get the max frequency...
// given { s:3, a:1, y:1 }, will return 3
function maxLetterFrequency(word) {
return Math.max(...Object.values(letterFrequency(word)));
}
Another simple problem to sort a sentence by frequency...
// given "She sells seashells by the seashore"
// returns ["seashells", "sells", "seashore", "She", "by", "the"]
function wordsOrderedByMaxLetterFrequency(sentence) {
let words = sentence.split(' ');
words.sort((a, b) => {
return maxLetterFrequency(b) - maxLetterFrequency(a);
});
return words;
}
The first word in the resulting array is the answer. You can retest max frequencies in that word to determine of the answer should be -1.
Demo...
// given "sassy", will return { s:3, a:1, y:1 }
function letterFrequency(word) {
return word.split('').reduce((acc, letter) => {
if (!acc[letter]) acc[letter] = 0;
acc[letter]++;
return acc;
}, {});
}
// given { s:3, a:1, y:1 }, will return 3
function maxLetterFrequency(word) {
return Math.max(...Object.values(letterFrequency(word)));
}
// given "She sells seashells by the seashore"
// returns ["seashells", "sells", "seashore", "She", "by", "the"]
function wordsOrderedByMaxLetterFrequency(sentence) {
let words = sentence.split(' ');
words.sort((a, b) => {
return maxLetterFrequency(b) - maxLetterFrequency(a);
});
return words;
}
const sentence = "She sells seashells by the seashore";
const sorted = wordsOrderedByMaxLetterFrequency(sentence);
console.log(sorted);
console.log('best word:', sorted[0]);
console.log('max freq in best word:', maxLetterFrequency(sorted[0]));
Upvotes: 2