You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于可变均值的钟形曲线为排序对象数组生成1-10步长0.5的分数

Assign Bell-Curve Scores to a Sorted Array (1-10, 0.5 Increments)

Got it, let's break down how to solve this problem effectively—even for large arrays with hundreds of elements. You have a pre-sorted list (best to worst) and want to assign scores that follow a normal (bell-curve) distribution, clamped between 1 and 10 with 0.5 step increments. Here's a step-by-step solution with code examples:

Core Approach

The key idea is to map each element's position in the sorted array to a normal distribution, then scale and adjust that value to fit your required range and step size:

  1. Calculate quantiles: For each element, compute its position as a quantile (percentage of the array it falls into) to avoid extreme edge values.
  2. Convert to Z-scores: Use the inverse normal distribution (PPF function) to turn quantiles into Z-scores (values from the standard normal curve, mean=0, stdDev=1).
  3. Scale to target range: Map Z-scores to your desired mean and standard deviation, then clamp values to 1-10.
  4. Adjust to 0.5 increments: Round the final score to the nearest 0.5 multiple.

Code Implementation (JavaScript)

We'll use math.js for reliable inverse normal distribution calculations (it's efficient even for large arrays). If you prefer no external dependencies, we'll also include an approximate inverse normal function.

First, install the library if you're using Node.js:

npm install mathjs

Then implement the scoring function:

const math = require('mathjs');

function assignBellCurveScores(sortedArray, mean = 5.5, stdDev = 1.5) {
  const arrayLength = sortedArray.length;
  if (arrayLength === 0) return [];

  return sortedArray.map((item, index) => {
    // Calculate quantile: (index + 0.5)/length avoids extreme 0/1 values
    const quantile = (index + 0.5) / arrayLength;
    // Get Z-score from inverse normal distribution
    const zScore = math.invNormal(quantile, 0, 1);
    // Map Z-score to our desired mean/stdDev, then clamp to 1-10
    let rawScore = mean + zScore * stdDev;
    rawScore = Math.max(1, Math.min(10, rawScore));
    // Round to nearest 0.5 increment
    const finalScore = Math.round(rawScore * 2) / 2;
    // Return the original object with updated score (kept as string per your structure)
    return { ...item, score: finalScore.toString() };
  });
}

// Example usage
const testArray = [
  { name: "John Doe", score: "" },
  { name: "Jane Doe", score: "" },
  { name: "Alice Smith", score: "" },
  { name: "Bob Johnson", score: "" },
  { name: "Charlie Brown", score: "" },
  { name: "Diana Prince", score: "" },
  { name: "Eve Adams", score: "" },
  { name: "Frank Miller", score: "" },
  { name: "Grace Lee", score: "" },
  { name: "Henry Wilson", score: "" }
];

const scoredResults = assignBellCurveScores(testArray, 5.5, 1.5);
console.log(scoredResults);

Option 2: No External Dependencies (Approximate Inverse Normal)

If you can't use math.js, use this approximation of the inverse normal distribution (Abramowitz and Stegun formula, accurate enough for most use cases):

// Approximate inverse normal distribution function
function approxInvNormal(quantile) {
  if (quantile <= 0) return -Infinity;
  if (quantile >= 1) return Infinity;

  const q = quantile - 0.5;
  const r = q * q;
  let z = q * (2.5066282746310002 + r * (-3.516396496826208 + r * (1.3835775186726904 + r * (-0.29331040638181613 + r * 0.027777777777777776))));
  z /= (1 + q * (1.4327881323044473 + q * (-0.12222222222222222 + q * 0.008333333333333333)));
  
  // Optional: Refine with one iteration of Newton-Raphson for better accuracy
  const normalPdf = Math.exp(-0.5 * z * z) / Math.sqrt(2 * Math.PI);
  z -= (math.normal(z) - quantile) / normalPdf;
  
  return z;
}

// Replace math.invNormal with approxInvNormal in the function above
function assignBellCurveScoresNoLib(sortedArray, mean = 5.5, stdDev = 1.5) {
  const arrayLength = sortedArray.length;
  if (arrayLength === 0) return [];

  return sortedArray.map((item, index) => {
    const quantile = (index + 0.5) / arrayLength;
    const zScore = approxInvNormal(quantile);
    let rawScore = mean + zScore * stdDev;
    rawScore = Math.max(1, Math.min(10, rawScore));
    const finalScore = Math.round(rawScore * 2) / 2;
    return { ...item, score: finalScore.toString() };
  });
}

Key Notes

  • Adjusting the curve: Tweak mean and stdDev to control the distribution. A mean of 5.5 centers scores in the middle, while a larger stdDev (e.g., 2) spreads scores more widely, and a smaller one (e.g., 1) clusters them closer to the mean.
  • Large arrays: Both implementations handle hundreds of elements smoothly—math.js is optimized for performance, and the approximation runs in constant time per element.
  • Edge handling: The (index + 0.5)/arrayLength quantile calculation ensures the first/last elements don't get extreme infinite Z-scores, keeping their scores within 1-10.

内容的提问来源于stack exchange,提问作者Irtesam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:43:31