# 數值%數顯示計算 ###### tags: `javascript` ❓ 狀況: 有六個比例%數要顯示,但如果數值來源是奇數,那麼六個%數總會有六個%數加起來不會是100%的狀況。 💡 想法: 計算比例後,為了顯示看起來正常,會在計算完比例後,檢查加總後是否為100%,若沒有會將最大比例分配給最小比例1%,讓整體加總成為100%。 ```typescript= /** * 為顯示做數值的比例計算。 * * 當計算比例時,出現 0% 以上 1% 以下的比例時,會自動上升為 1%,主要是處理直覺觀感的問題,只有 0 才會被計算成 0% * * 比例計算只要沒有小數點,無論如何都可能會出現湊不滿 100% 的情況 * 所以計算過程會犧牲掉比例值最大的對象,扣除他的 1% 填補在其他對象上 * * @param numbers 要做比例計算的數值陣列 * @returns 表示比例的整數陣列,數值從 0~100 的整數 */ export function getRatiosForDisplay ( numbers: number[] ) { /** 計算總計分 */ const total = numbers.reduce( ( p, v ) => p + v, 0 ) /** 生成原始比例值對象陣列,會轉換成 0 ~ 100 的數值,但保留小數點。做成物件型態方便改變數值,但不影響順序 */ const rawRatios = numbers.map( ( v ) => ( { value: ( v / total ) * 100 } ) ) /** 過濾出比率值大於 0% ,低於 1% 的對象。隨後稱為 "不滿對象",其餘稱為 "非不滿對象" */ const LessThan1P = rawRatios.filter( ( { value } ) => value && value < 1 ) /** 被處理過的 "不滿對象" 計數 */ let gainCount = 0 /** 所有 "不滿對象" 被加到 1% 時,被增加的總比例 */ const gains = LessThan1P.reduce( ( p, v ) => { if ( v.value < 1 ) { // 當判別為 "不滿對象" 時,將他們拉升到 1% ,並把增益出來的數值保存起來,並增加計數 const gain = 1 - v.value v.value = 1 gainCount++ return p + gain } // 為 "非不滿對象" 的話則不處理,回傳保存的數值 return p }, 0 ) /** 以 "非不滿對象" 的數量,平均化 gains,隨後用來扣除使用 */ const averageGain = gains / ( numbers.length - gainCount ) /** 最大比率的對象。預設值為所有比率值的第一位,用於比對 */ let maxRatioTgt = rawRatios[ 0 ] /** 用於最大比率對象的最終值,用所有其餘比率扣除,最終值將成為最大比率對象的值 */ let maxRatioFinal = 100 // 最終處理,將所有比率進行四捨五入,得出整數 for ( const ratio of rawRatios ) { // "不滿對象" 已經被整數化成 1 ,所以只處理 "非不滿對象",數值一定大於不等於 1 if ( ratio.value > 1 ) { /* "非不滿對象" 數值整數化,但要扣除 "不滿對象" 的平均增益 (就是拿 "非不滿對象" 的比率來填 "不滿對象" 的增益值) */ ratio.value = Math.round( ratio.value - averageGain ) } // 扣除掉最大比率的最終數值 maxRatioFinal -= ratio.value // 找尋最大比率的對象 if ( ratio.value > maxRatioTgt.value )maxRatioTgt = ratio } // 由於以上迴圈一定會扣到最大比率對象的數值,使 maxRatioFinal 變成負數,所以最後還得加回來,才會是正確的數值 maxRatioTgt.value = maxRatioFinal + maxRatioTgt.value const resule = rawRatios.map( ( { value } ) => value ) return resule } ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up