Add letter distribution and word length stats

This commit is contained in:
Robbie Antenesse 2017-12-17 13:48:48 -07:00
parent ae50f5f970
commit 526f22c329
5 changed files with 180 additions and 28 deletions

View File

@ -109,7 +109,7 @@ export function characterIsUppercase (character) {
return character === character.toUpperCase();
}
export function getWordsStats (words, partsOfSpeech) {
export function getWordsStats (words, partsOfSpeech, isCaseSensitive = false) {
const wordStats = {
numberOfWords: [
{
@ -117,6 +117,19 @@ export function getWordsStats (words, partsOfSpeech) {
value: words.length,
},
],
wordLength: {
shortest: 0,
longest: 0,
average: 0,
},
letterDistribution: [
// {
// letter: '',
// number: 0,
// percentage: 0.00,
// }
],
totalLetters: 0,
};
partsOfSpeech.forEach(partOfSpeech => {
@ -132,5 +145,53 @@ export function getWordsStats (words, partsOfSpeech) {
value: words.filter(word => !partsOfSpeech.includes(word.partOfSpeech)).length,
});
let totalLetters = 0;
const numberOfLetters = {};
words.forEach(word => {
const shortestWord = wordStats.wordLength.shortest;
const longestWord = wordStats.wordLength.longest;
const wordLetters = word.name.split('');
const lettersInWord = wordLetters.length;
totalLetters += lettersInWord;
if (shortestWord === 0 || lettersInWord < shortestWord) {
wordStats.wordLength.shortest = lettersInWord;
}
if (longestWord === 0 || lettersInWord > longestWord) {
wordStats.wordLength.longest = lettersInWord;
}
wordLetters.forEach(letter => {
const letterToUse = isCaseSensitive ? letter : letter.toLowerCase();
if (!numberOfLetters.hasOwnProperty(letterToUse)) {
numberOfLetters[letterToUse] = 1;
} else {
numberOfLetters[letterToUse]++;
}
});
});
wordStats.totalLetters = totalLetters;
wordStats.wordLength.average = totalLetters / words.length;
for (const letter in numberOfLetters) {
if (numberOfLetters.hasOwnProperty(letter)) {
const number = numberOfLetters[letter];
wordStats.letterDistribution.push({
letter,
number,
percentage: number / totalLetters,
});
}
}
wordStats.letterDistribution.sort((a, b) => {
if (a.percentage === b.percentage) return 0;
return (a.percentage > b.percentage) ? -1 : 1;
});
return wordStats;
}

View File

@ -0,0 +1,107 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
export const StatsSection = (props) => {
PropTypes.checkPropTypes({
stats: PropTypes.object.isRequired,
}, props, 'prop', 'StatsSection');
const {
numberOfWords,
wordLength,
letterDistribution,
totalLetters
} = props.stats;
return (
<div>
<div className='columns'>
<div className='column'>
<strong>Number of Words</strong>
<div className='field is-grouped is-grouped-multiline'>
{numberOfWords.map(stat => {
return (
<div className='control'>
<div className='tags has-addons'>
<span className='tag'>
{ stat.name }
</span>
<span className='tag is-white'>
{ stat.value }
</span>
</div>
</div>
);
})}
</div>
</div>
</div>
<div className='columns'>
<div className='column'>
<strong>Word Length</strong>
<div className='field is-grouped is-grouped-multiline'>
<div className='control'>
<div className='tags has-addons'>
<span className='tag'>
Shortest
</span>
<span className='tag is-white'>
{ wordLength.shortest }
</span>
</div>
</div>
<div className='control'>
<div className='tags has-addons'>
<span className='tag'>
Longest
</span>
<span className='tag is-white'>
{ wordLength.longest }
</span>
</div>
</div>
<div className='control'>
<div className='tags has-addons'>
<span className='tag'>
Average
</span>
<span className='tag is-white'>
{ wordLength.average }
</span>
</div>
</div>
</div>
</div>
</div>
<div className='columns'>
<div className='column'>
<strong>Letter Distribution</strong>
<div className='field is-grouped is-grouped-multiline'>
{letterDistribution.map(stat => {
return (
<div className='control'>
<div className='tags has-addons' title={ `${ stat.number } ${ stat.letter }'s total` }>
<span className='tag'>
{ stat.letter }
</span>
<span className='tag is-white'>
{ stat.percentage.toFixed(2) }
</span>
</div>
</div>
);
})}
</div>
<span>{ totalLetters } Total Letters</span>
</div>
</div>
</div>
);
}

View File

@ -8,6 +8,7 @@ import './styles.scss';
import { EditDictionaryModal } from '../../management/EditDictionaryModal';
import { DetailsSection } from './DetailsSection';
import { StatsSection } from './StatsSection';
const DISPLAY = {
NONE: false,
@ -28,7 +29,7 @@ export class DictionaryDetails extends Component {
alphabeticalOrder: PropTypes.array,
details: PropTypes.object,
settings: PropTypes.object,
stats: PropTypes.array,
stats: PropTypes.object,
updater: PropTypes.object,
updateDisplay: PropTypes.func,
}, props, 'prop', 'DictionaryDetails');
@ -88,27 +89,7 @@ export class DictionaryDetails extends Component {
case DISPLAY.STATS : {
displayJSX = (
<div className='columns'>
<div className='column'>
<strong>Number of Words</strong>
<div className='field is-grouped is-grouped-multiline'>
{this.props.stats.numberOfWords.map(stat => {
return (
<div className='control'>
<div className='tags has-addons'>
<span className='tag'>
{ stat.name }
</span>
<span className='tag is-white'>
{ stat.value }
</span>
</div>
</div>
);
})}
</div>
</div>
</div>
<StatsSection stats={ this.props.stats } />
);
break;
}

View File

@ -29,7 +29,7 @@ class App extends Component {
partsOfSpeech: dictionary.partsOfSpeech,
details: dictionary.details,
settings: dictionary.settings,
stats: [],
stats: {},
alphabeticalOrder: dictionary.alphabeticalOrder,
displayedWords: [],
@ -71,15 +71,15 @@ class App extends Component {
});
}
updateDisplayedWords () {
updateDisplayedWords (callback = () => {}) {
// const {searchIn, searchTerm, filteredPartsOfSpeech} = this.state.searchConfig;
// TODO: Sort out searching to remove this temporary solution.
dictionary.wordsPromise.then(words => {
this.setState({
displayedWords: words,
stats: getWordsStats(words, this.state.partsOfSpeech),
});
stats: getWordsStats(words, this.state.partsOfSpeech, this.state.settings.caseSensitive),
}, () => callback());
});
}

View File

@ -58,12 +58,15 @@ export class Updater {
updatedDetails['settings'] = this.dictionary.settings;
}
console.log(updatedDetails);
// console.log(updatedDetails);
if (updatedDetails.isEmpty()) {
reject('No dictionary details have changed.');
} else {
this.app.setState(updatedDetails, () => {
if (updatedDetails.hasOwnProperty('settings')) {
this.app.updateDisplayedWords();
}
resolve();
});
}