lotto lab 통계 수치 정상화
This commit is contained in:
@@ -63,6 +63,55 @@ const buildFrequencySeries = (frequency) => {
|
||||
return { series, max };
|
||||
};
|
||||
|
||||
const buildMetricsFromCounts = (counts) => {
|
||||
if (!counts?.length) return null;
|
||||
const total = counts.reduce((acc, value) => acc + value, 0);
|
||||
if (!total) return null;
|
||||
const min = Math.min(...counts);
|
||||
const max = Math.max(...counts);
|
||||
const range = max - min;
|
||||
const odd = counts.reduce(
|
||||
(acc, value, idx) => (idx % 2 === 0 ? acc + value : acc),
|
||||
0
|
||||
);
|
||||
const even = total - odd;
|
||||
const buckets = {
|
||||
'1-10': counts.slice(0, 10).reduce((a, b) => a + b, 0),
|
||||
'11-20': counts.slice(10, 20).reduce((a, b) => a + b, 0),
|
||||
'21-30': counts.slice(20, 30).reduce((a, b) => a + b, 0),
|
||||
'31-40': counts.slice(30, 40).reduce((a, b) => a + b, 0),
|
||||
'41-45': counts.slice(40, 45).reduce((a, b) => a + b, 0),
|
||||
};
|
||||
return { sum: total, min, max, range, odd, even, buckets };
|
||||
};
|
||||
|
||||
const buildMetricsFromFrequency = (frequency) => {
|
||||
if (!frequency?.length) return null;
|
||||
const counts = Array.from({ length: 45 }, () => 0);
|
||||
frequency.forEach((item) => {
|
||||
const number = Number(item?.number);
|
||||
const count = Number(item?.count) || 0;
|
||||
if (number >= 1 && number <= 45) {
|
||||
counts[number - 1] = count;
|
||||
}
|
||||
});
|
||||
return buildMetricsFromCounts(counts);
|
||||
};
|
||||
|
||||
const buildMetricsFromHistory = (items) => {
|
||||
if (!items?.length) return null;
|
||||
const counts = Array.from({ length: 45 }, () => 0);
|
||||
items.forEach((item) => {
|
||||
(item?.numbers ?? []).forEach((value) => {
|
||||
const number = Number(value);
|
||||
if (number >= 1 && number <= 45) {
|
||||
counts[number - 1] += 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
return buildMetricsFromCounts(counts);
|
||||
};
|
||||
|
||||
const toBucketEntries = (metrics) => {
|
||||
if (!metrics?.buckets) return [];
|
||||
const entries = Object.entries(metrics.buckets);
|
||||
@@ -95,19 +144,21 @@ const MetricBlock = ({ title, metrics }) => {
|
||||
<div className="lotto-metrics">
|
||||
<div className="lotto-metrics__head">
|
||||
<p className="lotto-metrics__title">{title}</p>
|
||||
<span className="lotto-metrics__sum">합계 {metrics.sum ?? '-'}</span>
|
||||
<span className="lotto-metrics__sum">
|
||||
총 출현 횟수 {metrics.sum ?? '-'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="lotto-metric-cards">
|
||||
<div className="lotto-metric-card">
|
||||
<p className="lotto-metric-card__label">최솟값</p>
|
||||
<p className="lotto-metric-card__label">최소 출현</p>
|
||||
<p className="lotto-metric-card__value">{metrics.min ?? '-'}</p>
|
||||
</div>
|
||||
<div className="lotto-metric-card">
|
||||
<p className="lotto-metric-card__label">최댓값</p>
|
||||
<p className="lotto-metric-card__label">최대 출현</p>
|
||||
<p className="lotto-metric-card__value">{metrics.max ?? '-'}</p>
|
||||
</div>
|
||||
<div className="lotto-metric-card">
|
||||
<p className="lotto-metric-card__label">범위</p>
|
||||
<p className="lotto-metric-card__label">출현 편차</p>
|
||||
<p className="lotto-metric-card__value">{metrics.range ?? '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -222,6 +273,14 @@ export default function Functions() {
|
||||
history: false,
|
||||
});
|
||||
const [error, setError] = useState('');
|
||||
const overallMetrics = useMemo(
|
||||
() => buildMetricsFromFrequency(stats?.frequency),
|
||||
[stats]
|
||||
);
|
||||
const historyMetrics = useMemo(
|
||||
() => buildMetricsFromHistory(history),
|
||||
[history]
|
||||
);
|
||||
|
||||
const refreshLatest = async () => {
|
||||
setLoading((s) => ({ ...s, latest: true }));
|
||||
@@ -240,8 +299,17 @@ export default function Functions() {
|
||||
setLoading((s) => ({ ...s, history: true }));
|
||||
setError('');
|
||||
try {
|
||||
const data = await getHistory(30);
|
||||
setHistory(data.items ?? []);
|
||||
const limit = 100;
|
||||
let offset = 0;
|
||||
const allItems = [];
|
||||
while (true) {
|
||||
const data = await getHistory(limit, offset);
|
||||
const items = data.items ?? [];
|
||||
allItems.push(...items);
|
||||
if (items.length < limit) break;
|
||||
offset += limit;
|
||||
}
|
||||
setHistory(allItems);
|
||||
} catch (e) {
|
||||
setError(e?.message ?? String(e));
|
||||
} finally {
|
||||
@@ -382,8 +450,11 @@ export default function Functions() {
|
||||
<p className="lotto-bonus">
|
||||
보너스 <strong>{latest.bonus}</strong>
|
||||
</p>
|
||||
{latest.metrics ? (
|
||||
<MetricBlock title="당첨 통계" metrics={latest.metrics} />
|
||||
{overallMetrics ? (
|
||||
<MetricBlock
|
||||
title="당첨 통계 (전체 회차)"
|
||||
metrics={overallMetrics}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
@@ -502,17 +573,12 @@ export default function Functions() {
|
||||
</button>
|
||||
</div>
|
||||
{result.numbers ? <NumberRow nums={result.numbers} /> : null}
|
||||
{result.metrics || latest?.metrics ? (
|
||||
{historyMetrics ? (
|
||||
<div className="lotto-compare">
|
||||
{result.metrics ? (
|
||||
<MetricBlock title="추천 통계" metrics={result.metrics} />
|
||||
) : null}
|
||||
{latest?.metrics ? (
|
||||
<MetricBlock
|
||||
title="당첨 통계 (최신 회차)"
|
||||
metrics={latest.metrics}
|
||||
/>
|
||||
) : null}
|
||||
<MetricBlock
|
||||
title="추천 통계 (히스토리)"
|
||||
metrics={historyMetrics}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{Array.isArray(result.items) && result.items.length ? (
|
||||
|
||||
Reference in New Issue
Block a user