const currentScores = {}; const currentBestClusterIndices = {}; const rescoreAll = target => pokemonData.forEach(({ name, jab, rgb }) => { currentScores[name] = { jab: { total: applyMetrics(jab.total, target.jab), clusters: jab.clusters.map(c => applyMetrics(c, target.jab)), }, rgb: { total: applyMetrics(rgb.total, target.rgb), clusters: rgb.clusters.map(c => applyMetrics(c, target.rgb)), }, }; }); const getBestClusterIndex = (pkmn, space, { sortMetric, scaleOption, sortOrder }) => { // get the scales const scales = scaleOption(pkmn[space]); // and multiply with the intended metric, and find the index of the best value return currentScores[pkmn.name][space].clusters .map((c, i) => [c[sortMetric] * scales[i], i]) .reduce((a, b) => sortOrder(a[0], b[0]) > 0 ? b : a)[1]; } const getBest = (number, space, clusterSettings, { sortMetric, scaleOption, sortOrder }) => { let valueExtractor; if (clusterSettings) { valueExtractor = pkmn => { const index = getBestClusterIndex(pkmn, space, clusterSettings); // save the index for rendering currentBestClusterIndices[pkmn.name] = { ...(currentBestClusterIndices[pkmn.name] || {}), [space]: index }; // and then get the *actual* score according to the sort metric const clusterScore = scaleOption(pkmn[space])[index] * currentScores[pkmn.name][space].clusters[index][sortMetric]; if (!clusterSettings.multWithTotal) { return clusterScore; } // and then multiply it with the total score if that's needed return clusterScore * currentScores[pkmn.name][space].total[sortMetric]; }; } else { // ignore scaleOption if not using clusters valueExtractor = pkmn => currentScores[pkmn.name][space].total[sortMetric]; } return pokemonData .slice() .sort((a, b) => sortOrder(valueExtractor(a), valueExtractor(b))) .slice(0, number); };