{"record":{"id":"b5388bdaad5dbed8","repo":"trekhleb/javascript-algorithms","slug":"items-and-weights-must-be-of-the-same-size","errorCode":null,"errorMessage":"Items and weights must be of the same size","messagePattern":"Items and weights must be of the same size","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/algorithms/statistics/weighted-random/weightedRandom.js","lineNumber":18,"sourceCode":"/**\n * Picks the random item based on its weight.\n * The items with higher weight will be picked more often (with a higher probability).\n *\n * For example:\n * - items = ['banana', 'orange', 'apple']\n * - weights = [0, 0.2, 0.8]\n * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return\n * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)\n *\n * @param {any[]} items\n * @param {number[]} weights\n * @returns {{item: any, index: number}}\n */\n/* eslint-disable consistent-return */\nexport default function weightedRandom(items, weights) {\n  if (items.length !== weights.length) {\n    throw new Error('Items and weights must be of the same size');\n  }\n\n  if (!items.length) {\n    throw new Error('Items must not be empty');\n  }\n\n  // Preparing the cumulative weights array.\n  // For example:\n  // - weights = [1, 4, 3]\n  // - cumulativeWeights = [1, 5, 8]\n  const cumulativeWeights = [];\n  for (let i = 0; i < weights.length; i += 1) {\n    cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);\n  }\n\n  // Getting the random number in a range of [0...sum(weights)]\n  // For example:\n  // - weights = [1, 4, 3]","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/statistics/weighted-random/weightedRandom.js#L1-L36","documentation":"weightedRandom(items, weights) requires exactly one weight per item; the first guard rejects any length mismatch. Weights are accumulated into cumulative sums and a random number in [0, sum] selects the item, so a missing or extra weight leaves the item-to-probability mapping undefined. The size check runs before the emptiness check, so mismatched non-empty arrays always produce this message rather than 'Items must not be empty'.","triggerScenarios":"weightedRandom(['a','b','c'], [1, 2]) (3 items, 2 weights); items extended without extending weights; weights built from a different data source or filtered separately from items.","commonSituations":"Weights read from config while items come from a database, items filtered (e.g. out-of-stock removed) without refiltering weights, or parallel arrays drifting apart across refactors.","solutions":["Log items.length and weights.length to find the drift","Rebuild both arrays from one source so they cannot diverge, e.g. derive weights with items.map(...)","When filtering items, filter index-aligned pairs and unzip afterwards","For uniform weights pass items.map(() => 1) instead of a hand-maintained array"],"exampleFix":"// before\nimport weightedRandom from './src/algorithms/statistics/weighted-random/weightedRandom';\nconst pick = weightedRandom(['a', 'b', 'c'], [1, 2]);\n// throws: 3 items vs 2 weights\n\n// after\nconst items = ['a', 'b', 'c'];\nconst weights = items.map((item) => (item === 'a' ? 1 : 2));\nconst pick = weightedRandom(items, weights);\n// lengths always match","handlingStrategy":"validation","validationCode":"if (!Array.isArray(items) || !Array.isArray(weights) || items.length !== weights.length) {\n  throw new TypeError('items and weights must be arrays of equal length');\n}\nweightedRandom(items, weights);","typeGuard":"const isWeightedPair = (items, weights) =>\n  Array.isArray(items) && Array.isArray(weights)\n  && items.length === weights.length && items.length > 0;","tryCatchPattern":"try {\n  pick = weightedRandom(items, weights);\n} catch (e) {\n  if (e.message === 'Items and weights must be of the same size') {\n    pick = { item: items[0], index: 0 }; // degrade to first item\n  } else {\n    throw e;\n  }\n}","preventionTips":["Zip items and weights into one structure instead of parallel arrays","When filtering, filter (item, index) pairs so alignment survives","Assert equal lengths in a unit test on the config loader"],"tags":["statistics","random-sampling","array-length-mismatch","validation"],"backgroundTag":"array-length-mismatch","analyzedSha":"85293e3e2b88f4d2ce330d956b139cf628aa1e82","analyzedAt":"2026-08-24T05:59:10.417Z","schemaVersion":2},"datasetVersion":"2026-08-24T07:17:09.176Z"}