# Stateless Maximum Beauty of String implementation

Inspired by The Beauty and the Strings question, I tried to implement the "Maximum Beauty of String" in a stateless fashion using ES6. Unfortunately, I ran into two places where I had to assign variables.

The questions I have:

• How can I remove the state in the reducer for mapLettersByCount?
• How can one use generators without assigning it to a variable? (see points variable in the maxBeauty function) Is this even considered state in this situation?

Code:

const EMPTY_STRING = '';
const LETTERS_ONLY = /[a-z]/i;

function mapLettersByCount(sentence) {
return sentence.split(EMPTY_STRING)
.filter(letter => LETTERS_ONLY.test(letter))
.map(letter => [letter.toUpperCase(), 1])
.reduce((letterCount, [key, count]) => {
letterCount[key] = (letterCount[key] || 0) + count;
return letterCount;
}, {});
}

function * downCounter(maxValue) {
yield maxValue;
yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}

export function maxBeauty(sentence = "") {
const points = downCounter(26);
return Object.values(mapLettersByCount(sentence))
.sort().reverse()
.reduce((score, count) => score + count * points.next().value, 0);
}


Test Cases:

import {maxBeauty} from './beauty';

describe('The maximum beauty', () => {
it('should calculate for a word', () => {
expect(maxBeauty('AbBCcC')).toBe(152);
});

it('should calculate ignoring spaces', () => {
expect(maxBeauty('This is from Facebook Hacker Cup 2013.'))
.toBe(551);
});

it('should calculate ignoring punctuation', () => {
.toBe(491);
});
});


How can I remove the state in the reducer for mapLettersByCount?

Return a new object on each iteration. Not optimal, but we're talking functional anyways. You can use object destructuring to do a shallow copy of the object. A more verbose version would be Object.assign. Then use computed keys to assign a dynamic key.

function mapLettersByCount(sentence) {
return sentence.split(EMPTY_STRING)
.filter(letter => LETTERS_ONLY.test(letter))
.map(letter => [letter.toUpperCase(), 1])
.reduce((letterCount, [key, count]) => ({
...letterCount,
[key]: (letterCount[key] || 0) + count
}), {});
}


How can one use generators without assigning it to a variable? (see points variable in the maxBeauty function) Is this even considered state in this situation?

I believe that it is stateful since one call to points.next() does not return the same result as the next call. But I may be wrong.

One way you could do this is compute the points by subtracting the reducer's index from a constant 26. I believe it won't violate the rules of functional programming because

1. this 26 is a constant value
2. it's technically a closure scenario, similar to your other constants and
3. index is provided as an argument to the callback.

And it would look like this:

const POINTS = 26;

export function maxBeauty(sentence = "") {
return Object.values(mapLettersByCount(sentence))
.sort()
.reverse()
.reduce((score, count, index) => score + count * (POINTS - index), 0);
}