js red envelope algorithm [reprint]

Source address: https://juejin.im/post/5ae413946fb9a07a9c03f7f7

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        class RandomSplit {
            constructor(num) {
                // actual total
                this.num = this.getNum(num);
                // gain
                try {
                    this.multiple = this.num.toString().split('.')[1].length;
                } catch (e) {
                    this.multiple = 0;
                }
                // total number for integer operations
                this.calcNum = this.num * Math.pow(10, this.multiple);
            }
            // Determine whether it is a number (take "is-number")
            isNumber(num) {
                let number = +num;
                if ((number - number) !== 0) {
                    return false;
                }
                if (number === num) {
                    return true;
                }
                if (typeof num === 'string') {
                    if (number === 0 && num.trim() === '') {
                        return false;
                    }
                    return true;
                }
                return false;
            }
            // get the number
            getNum(num, defaultNum = 0) {
                return this.isNumber(num) ? (+num) : defaultNum;
            }
            //The number of equal shares, the accuracy of the equal share, whether to directly return the enlarged integer
            average(n, precision, isInt) {
                precision = Math.floor(this.getNum(precision, 0));
                n = Math.floor(this.getNum(n));
                let calcNum = this.calcNum * Math.pow(10, precision < 0 ? 0 : precision);
                // The number of copies exceeds the calculated total number after magnification, that is, the case of insufficient points
                if (n > calcNum) {
                    return [];
                } else {
                    let index = 0;
                    // average
                    let avg = Math.floor(calcNum / n);
                    // remainder
                    let rest = calcNum % n;
                    // remaining number fill interval
                    let gap = Math.round((n - rest) / rest) + 1;
                    // original average array
                    let result = Array(n).fill(avg);
                    //
                    while (rest > 0) {
                        index = (--rest) * gap;
                        result[index >= n ? (n - 1) : index]++;
                    }
                    // return the zoomed result array
                    if (isInt) {
                        return result;
                    }
                    // Return the result array that meets the precision requirements after processing
                    return result.map((item) => {
                        return (item / Math.pow(10, this.multiple + precision));
                    });
                }
            }
            // The number of random divisions, the division accuracy
            split(n, precision) {
                n = Math.floor(this.getNum(n));
                precision = Math.floor(this.getNum(precision, 0));
                // evenly
                let arr = this.average(n, precision, true);
                let arrResult = arr.concat();
                for (let i = 0; i < arr.length; i++) {
                    //total amount given
                    let num = Math.floor(Math.random() * arr[i]);
                    // Amount to give to left neighbor
                    let numLeft = Math.floor(Math.random() * num);
                    // Amount to give to right neighbor
                    let numRight = num - numLeft;
                    // First and last index processing
                    let iLeft = i === 0 ? (arr.length - 1) : (i - 1);
                    let iRight = i === (arr.length - 1) ? 0 : (i + 1);
                    arrResult[i] -= num;
                    arrResult[iLeft] += numLeft;
                    arrResult[iRight] += numRight;
                }
                // shrink to original size
                return arrResult.map((item) => {
                    return (item / Math.pow(10, this.multiple + precision));
                });
            }
        }
        var r = new RandomSplit (250);
        console.log(r.average(3))
        console.log(r.split(3))
    </script>
</body>

</html>

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325239041&siteId=291194637