mirror of
https://github.com/Alamantus/Lexiconga.git
synced 2025-06-21 00:26:39 +02:00
Add letter distribution and word length stats
This commit is contained in:
parent
ae50f5f970
commit
526f22c329
5 changed files with 180 additions and 28 deletions
|
@ -109,7 +109,7 @@ export function characterIsUppercase (character) {
|
||||||
return character === character.toUpperCase();
|
return character === character.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWordsStats (words, partsOfSpeech) {
|
export function getWordsStats (words, partsOfSpeech, isCaseSensitive = false) {
|
||||||
const wordStats = {
|
const wordStats = {
|
||||||
numberOfWords: [
|
numberOfWords: [
|
||||||
{
|
{
|
||||||
|
@ -117,6 +117,19 @@ export function getWordsStats (words, partsOfSpeech) {
|
||||||
value: words.length,
|
value: words.length,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
wordLength: {
|
||||||
|
shortest: 0,
|
||||||
|
longest: 0,
|
||||||
|
average: 0,
|
||||||
|
},
|
||||||
|
letterDistribution: [
|
||||||
|
// {
|
||||||
|
// letter: '',
|
||||||
|
// number: 0,
|
||||||
|
// percentage: 0.00,
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
totalLetters: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
partsOfSpeech.forEach(partOfSpeech => {
|
partsOfSpeech.forEach(partOfSpeech => {
|
||||||
|
@ -132,5 +145,53 @@ export function getWordsStats (words, partsOfSpeech) {
|
||||||
value: words.filter(word => !partsOfSpeech.includes(word.partOfSpeech)).length,
|
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;
|
return wordStats;
|
||||||
}
|
}
|
||||||
|
|
107
src/components/display/DictionaryDetails/StatsSection.jsx
Normal file
107
src/components/display/DictionaryDetails/StatsSection.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import './styles.scss';
|
||||||
|
|
||||||
import { EditDictionaryModal } from '../../management/EditDictionaryModal';
|
import { EditDictionaryModal } from '../../management/EditDictionaryModal';
|
||||||
import { DetailsSection } from './DetailsSection';
|
import { DetailsSection } from './DetailsSection';
|
||||||
|
import { StatsSection } from './StatsSection';
|
||||||
|
|
||||||
const DISPLAY = {
|
const DISPLAY = {
|
||||||
NONE: false,
|
NONE: false,
|
||||||
|
@ -28,7 +29,7 @@ export class DictionaryDetails extends Component {
|
||||||
alphabeticalOrder: PropTypes.array,
|
alphabeticalOrder: PropTypes.array,
|
||||||
details: PropTypes.object,
|
details: PropTypes.object,
|
||||||
settings: PropTypes.object,
|
settings: PropTypes.object,
|
||||||
stats: PropTypes.array,
|
stats: PropTypes.object,
|
||||||
updater: PropTypes.object,
|
updater: PropTypes.object,
|
||||||
updateDisplay: PropTypes.func,
|
updateDisplay: PropTypes.func,
|
||||||
}, props, 'prop', 'DictionaryDetails');
|
}, props, 'prop', 'DictionaryDetails');
|
||||||
|
@ -88,27 +89,7 @@ export class DictionaryDetails extends Component {
|
||||||
|
|
||||||
case DISPLAY.STATS : {
|
case DISPLAY.STATS : {
|
||||||
displayJSX = (
|
displayJSX = (
|
||||||
<div className='columns'>
|
<StatsSection stats={ this.props.stats } />
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class App extends Component {
|
||||||
partsOfSpeech: dictionary.partsOfSpeech,
|
partsOfSpeech: dictionary.partsOfSpeech,
|
||||||
details: dictionary.details,
|
details: dictionary.details,
|
||||||
settings: dictionary.settings,
|
settings: dictionary.settings,
|
||||||
stats: [],
|
stats: {},
|
||||||
alphabeticalOrder: dictionary.alphabeticalOrder,
|
alphabeticalOrder: dictionary.alphabeticalOrder,
|
||||||
|
|
||||||
displayedWords: [],
|
displayedWords: [],
|
||||||
|
@ -71,15 +71,15 @@ class App extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDisplayedWords () {
|
updateDisplayedWords (callback = () => {}) {
|
||||||
// const {searchIn, searchTerm, filteredPartsOfSpeech} = this.state.searchConfig;
|
// const {searchIn, searchTerm, filteredPartsOfSpeech} = this.state.searchConfig;
|
||||||
|
|
||||||
// TODO: Sort out searching to remove this temporary solution.
|
// TODO: Sort out searching to remove this temporary solution.
|
||||||
dictionary.wordsPromise.then(words => {
|
dictionary.wordsPromise.then(words => {
|
||||||
this.setState({
|
this.setState({
|
||||||
displayedWords: words,
|
displayedWords: words,
|
||||||
stats: getWordsStats(words, this.state.partsOfSpeech),
|
stats: getWordsStats(words, this.state.partsOfSpeech, this.state.settings.caseSensitive),
|
||||||
});
|
}, () => callback());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,12 +58,15 @@ export class Updater {
|
||||||
updatedDetails['settings'] = this.dictionary.settings;
|
updatedDetails['settings'] = this.dictionary.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(updatedDetails);
|
// console.log(updatedDetails);
|
||||||
|
|
||||||
if (updatedDetails.isEmpty()) {
|
if (updatedDetails.isEmpty()) {
|
||||||
reject('No dictionary details have changed.');
|
reject('No dictionary details have changed.');
|
||||||
} else {
|
} else {
|
||||||
this.app.setState(updatedDetails, () => {
|
this.app.setState(updatedDetails, () => {
|
||||||
|
if (updatedDetails.hasOwnProperty('settings')) {
|
||||||
|
this.app.updateDisplayedWords();
|
||||||
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue