【问题标题】:How to extract a set of isolated 2D arrays from a larger 2D array?如何从更大的二维数组中提取一组孤立的二维数组?
【发布时间】:2021-08-04 04:58:55
【问题描述】:

假设我有一个 2D 数组,其中填充了很多空白,但这些空白之间包含较小的独立 2D 数组。例如:

var aVO = [
  ["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"],
  ["", "", "", "", "", "", "", "", ""],
  [1, 2, 3, "", "", "", "", "", ""],
  [4, 5, 6, "", "", "a", "b", "", ""],
  [7, 8, 9, "", "", "c", "d", "", 1],
  ["", "", "", "", "", "", "", "", 2],
  ["", "", "z", "y", "", "", "", "", 3],
  ["", "x", "w", "v", "", 7, 7, 7, ""],
  ["", "", "", "", "", "", "", "", ""],
  ["", "", "", "", "", "", "", "", ""],
  ["", "A1", "B1", "", "", "", "", "", ""],
  ["", "A2", "B2", "C2", "", "", "HELLO", "", ""]
]

我有兴趣将其转换为 8 个二维数组:

[["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"]]
[[1,2,3],[4,5,6],[7,8,9]]
[["a","b"],["c","d"]]
[[1],[2],[3]]
[["", "z","y"],["x","w", "v"]]
[[7,7,7]]
[["A1","B1",""],["A2","B2","C2"]]
[["HELLO"]]

提取这些较小的二维数组的最佳方法是什么?我正在考虑逐行迭代,但很难想象如何优雅地提取像[["", "z","y"],["x","w","v"]] 这样的数据(注意“x”如何不在“z”的正下方,因此生成的二维数组需要反映这种转变)。感谢您的帮助!

【问题讨论】:

  • 您要对这些元素进行分组的逻辑非常不清楚,因此请首先正确解释。
  • @CBroe 数据包含值的“孤岛”,由空字符串分隔。 OP想要提取这些岛屿。结果应该是一个恒定行大小的二维数组列表,这解释了为什么需要包含z y 行中的空字符串。

标签: javascript arrays parsing


【解决方案1】:

这是一种使用SetMap 实例来跟踪单元组的方法:

  • 从二维数组中创建单元格
  • 创建一个空的Map,我们将为每个单元格存储其所属组的值
  • 循环遍历每个单元格
    • 如果一个单元格是空的,转到下一个
    • 如果单元格有值
      • 为其创建一个组。该组标记左上角和右下角位置并跟踪属于它的一组单元格。
      • 检查哪些相邻单元格已属于某个组
      • 将新创建的组与为相邻单元格找到的所有组合并
  • Map 收集所有唯一组
  • 对于每个唯一组,从初始网格中切出其左上角和右下角之间的部分

const Cell = memo(
  (r, c) => ({ r, c }),
  ([r, c]) => `${r}_${c}`
);

Cell.neighbors = ({ r, c }) => [
  Cell(r, c + 1), // Right
  Cell(r + 1, c), // Down
  Cell(r, c - 1), // Left
  Cell(r - 1, c), // Up
];

// Create a single-cell group
const Group = (cell) => ({
  minR: cell.r,
  maxR: cell.r + 1,
  minC: cell.c,
  maxC: cell.c + 1,
  cells: new Set([cell])
});

// Merge two groups into a new one
Group.merge = (g1, g2) => ({
  minR: Math.min(g1.minR, g2.minR),
  maxR: Math.max(g1.maxR, g2.maxR),
  minC: Math.min(g1.minC, g2.minC),
  maxC: Math.max(g1.maxC, g2.maxC),
  cells: new Set([ ...g1.cells, ...g2.cells ])
});

// Take a grid and slice out the part covered by a group
Group.extractFromGrid = grid => ({ minR, maxR, minC, maxC }) => grid
  .slice(minR, maxR)
  .map(row => row.slice(minC, maxC));

// Create all cells with their values
const grid = getData();
const allCells = grid.flatMap(
  (row, ri) => row.map(
    (value, ci) => Cell(ri, ci)
  )
);

const groupPerCell = new Map();

allCells.forEach(current => {
  const inIsland = grid[current.r][current.c] !== "";
  if (inIsland) {  
    const newGroup = Cell
      .neighbors(current)
      .filter(c => groupPerCell.has(c))
      .map(c => groupPerCell.get(c))
      .reduce(Group.merge, Group(current));
   
    // Store a reference to the group for each member
    newGroup.cells.forEach(c => {
      groupPerCell.set(c, newGroup);
    });
  }  
});

const allGroups = [...new Set(groupPerCell.values())];
const allValues = allGroups.map(Group.extractFromGrid(grid));

console.log(allValues);



function memo(f, hash) {
  const cache = {};
  
  return (...args) => {
    const k = hash(args);
    if (!cache[k]) cache[k] = f(...args);
    
    return cache[k];
  }
}

function getData() { return [
  ["col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9"],
  ["", "", "", "", "", "", "", "", ""],
  [1, 2, 3, "", "", "", "", "", ""],
  [4, 5, 6, "", "", "a", "b", "", ""],
  [7, 8, 9, "", "", "c", "d", "", 1],
  ["", "", "", "", "", "", "", "", 2],
  ["", "", "z", "y", "", "", "", "", 3],
  ["", "x", "w", "v", "", 7, 7, 7, ""],
  ["", "", "", "", "", "", "", "", ""],
  ["", "", "", "", "", "", "", "", ""],
  ["", "A1", "B1", "", "", "", "", "", ""],
  ["", "A2", "B2", "C2", "", "", "HELLO", "", ""]
]; }

【讨论】:

  • 这是一个如此出色而优雅的解决方案,非常感谢您抽出宝贵时间编写并解释它。识别“相邻”细胞绝对是要走的路。我一直回到你的解决方案来吸收它(我更像是一个 ES5 开发人员而不是 ES6,所以我从你的回答中学到了很多东西)。再次感谢!!
  • 这是我见过的关于 JS 最神奇的答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-27
  • 2016-08-26
相关资源
最近更新 更多