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

如何从二维矩阵中随机选取N个无重复的行/列或x/y坐标?

二维矩阵随机选取N个无重复坐标的实现方案

问题描述

现有二维矩阵示例如下:
data = [["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"]]
需求是从矩阵中随机选取N个无重复的(x, y)索引坐标,原实现仅支持固定选取2个坐标,需扩展为支持任意合法N的通用方案。

原固定2个坐标的实现代码如下:

const data = [["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"]];

function combinations(data) {
  const i11 = Math.floor(Math.random() * data.length);
  const i12 = Math.floor(Math.random() * data[i11].length);

  const dataLength = data[i11].length > 1 ? data.length : data.length - 1;

  let i21 = Math.floor(Math.random() * dataLength);
  if (i21 >= i11 && data[i11].length === 1) ++i21;

  const innerDataLength = i21 === i11 ? data[i21].length - 1 : data[i21].length;
  let i22 = Math.floor(Math.random() * innerDataLength);
  if (i21 === i11 && i22 >= i12) ++i22;
  
  return [[i11, i12], [i21, i22]];
}

通用扩展方案

这里提供两种适用不同场景的实现:

方案1:全坐标洗牌法(性能稳定,推荐大多数场景使用)

实现思路:先穷举所有合法坐标,再通过Fisher-Yates洗牌算法打乱顺序,取前N个即可,完全避免重复判断,不会出现极端场景下的性能问题。
代码实现:

// Fisher-Yates 洗牌算法,打乱数组顺序
function shuffle(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

function getRandomCoordinates(data, n) {
  // 先收集所有合法坐标
  const allCoords = [];
  for (let x = 0; x < data.length; x++) {
    for (let y = 0; y < data[x].length; y++) {
      allCoords.push([x, y]);
    }
  }
  // 校验n的合法性
  if (n > allCoords.length) {
    throw new Error(`选取数量不能超过总坐标数:${allCoords.length}`);
  }
  // 洗牌后取前n个
  return shuffle(allCoords).slice(0, n);
}

测试代码:

const data = [["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"]];
// 测试选取3个坐标
console.log(getRandomCoordinates(data, 3));

// 10000次重复测试,验证无重复
for (let i = 0; i < 10000; i++) {
  const coords = getRandomCoordinates(data, 3);
  const uniqueStr = new Set(coords.map(c => `${c[0]},${c[1]}`));
  if (uniqueStr.size !== coords.length) {
    console.log('测试失败,出现重复坐标');
  }
}

方案2:随机生成+去重法(适合N远小于总坐标数的场景)

实现思路:每次随机生成坐标后,通过Set记录已生成的坐标字符串,直到收集到N个不同的坐标,实现非常简单,小N场景下效率更高。
代码实现:

function getRandomCoordinates(data, n) {
  // 先计算总坐标数,校验合法性
  const total = data.reduce((sum, row) => sum + row.length, 0);
  if (n > total) {
    throw new Error(`选取数量不能超过总坐标数:${total}`);
  }
  const result = [];
  const used = new Set();
  while (result.length < n) {
    const x = Math.floor(Math.random() * data.length);
    const y = Math.floor(Math.random() * data[x].length);
    const key = `${x},${y}`;
    if (!used.has(key)) {
      used.add(key);
      result.push([x, y]);
    }
  }
  return result;
}

两种方案选择建议

  • 如果矩阵总元素量不大,或者N接近总元素量,优先选方案1,性能更稳定
  • 如果矩阵非常大,且N远小于总元素量,选方案2,避免生成全量坐标的内存和时间开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 22:45:00