首页 > 解决方案 > 如何从更大的二维数组中提取一组孤立的二维数组?

问题描述

假设我有一个 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", "", ""]
]

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

[["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”的正下方,因此生成的二维数组需要反映这种转变)。谢谢你的帮助!

标签: javascriptarraysparsing

解决方案


这是一种使用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", "", ""]
]; }


推荐阅读