如何获得这种格式的二维数组?

How can I get a two dimensional array in this format?

我的输入数组:

["red", "blue", "blue", "blue", "blue", "red", "blue", "blue", "blue", "blue", "blue", "blue", "red", "red", "red", "red", "red", "blue", "red", "red"]

我得到了一个这种格式的数组。

    [
      ["red", "blue", "red", "blue", "red", "blue", "red", "", "", "", "", "", "", "", "", "", "", "", "", ""],
      ["red","blue","","","","","","","","","","","","","","","","","",""],
      ["red","blue","","","","","","","","","","","","","","","","","",""],
      ["red","blue","","","","","","","","","","","","","","","","","",""],
      ["red","blue","","","","","","","","","","","","","","","","","",""],
      ["","blue","","","","","","","","","","","","","","","","","",""],
    ]

我想要这种格式的结果数组

    [
       ["red", "blue", "red", "blue", "red", "blue", "red", "", "", "", "", "", "", "", 
         "", "", "", "", "", ""],
       ["","blue","","blue","red","","red","","","","","","","","","","","","",""],
       ["","blue","","blue","red","","","","","","","","","","","","","","",""],
       ["","blue","","blue","red","","","","","","","","","","","","","","",""],
       ["","","","blue","red","","","","","","","","","","","","","","",""],
       ["","","","blue","","","","","","","","","","","","","","","",""],
     ]

这是我的代码:

const findArrayColorDuplicate = function (array) {
  const dupIndexes = new Set();
  const dupValues = new Set();
  for (let i = 0; i < array.length - 1; i++) {
    if (array[i] === array[i + 1]) {
      dupIndexes.add(i + 1)
      dupValues.add({ index: i + 1, number: array[i + 1] });
    }
  }
  return { index: [...dupIndexes], value: [...dupValues] }
}
const formatArrayDuplicate = function (arr) {
  const results_history = []
  const arr_1 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];
  const arr_2 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];
  const arr_3 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];
  const arr_4 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];
  const arr_5 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];
  const arr_6 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', ''];

  // Find array duplicate in range
  const dupArray_1 = findArrayColorDuplicate(arr)
  // *************************** Row 1 ***************************
  for (let i = 0; i < dupArray_1.index.length; i++) {
    for (let j = 0; j < arr.length; j++) {
      if (j === dupArray_1.index[i]) {
        arr_1[j] = arr[j]
        arr[j] = ''
      }
    }
    const $dup = dupArray_1.value.find(value => value.index ===
      dupArray_1.index[i])
    arr_2[$dup.index] = $dup.number
  }


  const arr_row_1 = arr.filter(value => value !== 0)
  for (let i = 0; i < 20; i++) {
    if (arr_row_1.length < 20)
      arr_row_1.push(0)
  }
  // *************************** Row 2 ***************************
  const arr_row_2 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '']
  for (let i = 0; i < dupArray_1.index.length; i++) {
    const t = arr_row_1.findIndex(value => value === dupArray_1.value[i].number)
    arr_row_2[t] = dupArray_1.value[i].number
  }


  // *************************** Row 3 ***************************
  const dupArray_2 = findArrayColorDuplicate(arr_2)
  const arr_row_3 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '']
  for (let i = 0; i < dupArray_2.index.length; i++) {
    const t = arr_row_2.findIndex(value => value === dupArray_2.value[i].number)
    arr_row_3[t] = dupArray_2.value[i].number

    const $dup = dupArray_2.value.find(value => value.index ===
      dupArray_2.index[i])
    arr_3[$dup.index] = $dup.number
  }

  // *************************** Row 4 ***************************
  const dupArray_3 = findArrayColorDuplicate(arr_3)
  const arr_row_4 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '']
  for (let i = 0; i < dupArray_3.index.length; i++) {
    const t = arr_row_3.findIndex(value => value === dupArray_3.value[i].number)
    arr_row_4[t] = dupArray_3.value[i].number

    const $dup = dupArray_3.value.find(value => value.index ===
      dupArray_3.index[i])
    arr_4[$dup.index] = $dup.number
  }

  // *************************** Row 4 ***************************
  const dupArray_4 = findArrayColorDuplicate(arr_4)
  const arr_row_5 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '']
  for (let i = 0; i < dupArray_4.index.length; i++) {
    const t = arr_row_4.findIndex(value => value === dupArray_4.value[i].number)
    arr_row_5[t] = dupArray_4.value[i].number

    const $dup = dupArray_4.value.find(value => value.index ===
      dupArray_4.index[i])
    arr_5[$dup.index] = $dup.number
  }

  // *************************** Row 4 ***************************
  const dupArray_5 = findArrayColorDuplicate(arr_5)
  const arr_row_6 = ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '']
  for (let i = 0; i < dupArray_5.index.length; i++) {
    const t = arr_row_5.findIndex(value => value === dupArray_5.value[i].number)
    arr_row_6[t] = dupArray_5.value[i].number

    const $dup = dupArray_5.value.find(value => value.index ===
      dupArray_5.index[i])
    arr_6[$dup.index] = $dup.number
  }

  results_history[0] = arr_row_1;
  results_history[1] = arr_row_2;
  results_history[3] = arr_row_3;
  results_history[4] = arr_row_4;
  results_history[5] = arr_row_5;
  results_history[6] = arr_row_6;
  return results_history;
}

const arr = ["red", "blue", "blue", "blue", "blue", "red", "blue", "blue",
  "blue", "blue", "blue", "blue", "red", "red", "red", "red", "red", "blue", "red",
  "red"];
formatArrayDuplicate(arr);

下面介绍的是实现所需 objective.

的一种可能方法

代码段

// helper method
const myMerge = (c, e, r) => {
  // initialize result "row"
  const res = [];
  
  // iterate upto column "c"
  for (let i = 0; i < c; i++) {
    // populate each elt in "res"
    res[i] = (
      r && r?.length && i < r.length
      ? r[i]
      : '___'   // replace this with ""
    );
  };
  
  // populate the last elt in "res"
  res[c] = e;
  
  return res;
};

// assignment is done
const doMyAssignmentWork = arr => {
  // result 2d array, initialized with 0-th elt
  const res2d = [[arr[0]]];
  
  // markers for row & col in res2d
  let col = 0, row = 0;
  
  // loop through the input array
  for (let i = 1; i < arr.length; i++) {
    // note the previous & current element
    const prev = arr[i-1], elt = arr[i];
    
    // if previous & current match (ie, dupe)
    if (prev === elt) {
      row++;
      res2d[row] = myMerge(col, elt, res2d[row]);
    } else {
      // previous & current are different
      col++;
      row = 0;
      res2d[row][col] = elt;
    }
  };
  return res2d;
};

const myArray = [
  'red', 'blue', 'red', 'red', 'blue', 'red', 'blue', 'blue', 'blue',
  'blue', 'red', 'red', 'blue', 'red', 'blue', 'blue', 'red', 'red',
  'red', 'red'
];

console.log(
  'given input: ',
  JSON.stringify(myArray),
  '\n\ndesired result:\n',
  doMyAssignmentWork(myArray)
  .map(x => x.join())
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

说明

在上面的代码段中添加了内联评论。

PS:请将'___'替换为empty-string""。前者仅用于将结果以相对容易验证的方式显示在片段中。

这是一个使用递归函数的潜在答案。那些是相当强大的!我添加了一些 css 来设置输出样式,使其更易于可视化。

const myList = ["red", "blue", "blue", "blue", "blue", "red", "blue", "blue", "blue", "blue", "blue", "blue", "red", "red", "red", "red", "red", "blue", "red", "red"];
const target = document.getElementById('target');


const out = ColorSplit(myList, [
  []
], 0, 0);

function ColorSplit(input, output, index, count) {
  //If the value of the input is the same as the previous value, we want to add it to the currently selected array - this is determined by the index varaible.
  if (count == 0 || input[count - 1] == input[count])
    output[index].push(input[count]);
  //If the previous value in the input is different from our current value, we want to make a new arry and add it to that. We also increment the index, as this move the pointer to the array we are currently focused on.
  else {
    index += 1;
    output[index] = [input[count]];
  }
  
  //This is where we do the recursiveness. If we have not finished going through the entire array, we call ColorSplit again. Else we return.
  return count < input.length - 1 ? ColorSplit(input, output, index, count += 1) : output;
}

//Displaying the results -- not part of the answer
for (var x = 0; x < out.length; x++) {
  let comp = "<div>";
  out[x].forEach(i => {
    comp += `<span class="${i}">${i}</span>`;
  });
  comp += "</div>";
  target.innerHTML += comp;
}
#target {
  display: inline-flex;
  flex-direction: row;
}

#target div {
  display: inline-flex;
  flex-direction: column;
}

span {
  background-color: grey;
  width: 2em;
  height: 2em;
  display: inline-flex;
  text-align: center;
  justify-content: center;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
<div id="target"></div>

我们可以在一些可重用的函数上执行此操作。 grouppadtranspose 都是对许多项目真正有用的函数。有了它们,我们可以相当简单地创建 regroup

const group = (xs, idx = xs .findIndex (x => x !== xs [0])) =>
  xs .length == 0 ? [] : idx < 0 ? [xs] : [xs .slice (0, idx), ... group (xs .slice (idx))]

const pad = (n, v) => (xs) => 
  [...xs, ...Array (Math .max (n - xs.length, 0)) .fill (v)]

const transpose = (xs) => 
  [... xs [0]] .map ((_, i) => [... xs] .map (r => r [i]))

const regroup = (xs) => {
  const grouped = group (xs)
  const length = Math .max (... grouped .map (g => g.length))
  const ys = grouped .map (pad (length, ''))
  return transpose (ys) .map (pad (xs .length, ''))
}

const input = ["red", "blue", "blue", "blue", "blue", "red", "blue", "blue", "blue", "blue", "blue", "blue", "red", "red", "red", "red", "red", "blue", "red", "red"]

console .log (regroup (input))
.as-console-wrapper {max-height: 100% !important; top: 0}

group 递归地获取一个数组并将其分解为 sub-arrays 个相等的顺序值。所以你原来的会变成

[
  ["red"],
  ["blue", "blue", "blue", "blue"],
  ["red"], 
  ["blue", "blue", "blue", "blue", "blue", "blue"],
  ["red", "red", "red", "red", "red"],
  ["blue"], 
  ["red", "red"]
]

但是这些参差不齐的数组并不那么容易处理,所以我们使用 pad 将它们填充到最长的数组的长度,得到:

[
  ["red",  "",     "",     "",     "",     ""    ], 
  ["blue", "blue", "blue", "blue", "",     ""    ], 
  ["red",  "",     "",     "",     "",     ""    ], 
  ["blue", "blue", "blue", "blue", "blue", "blue"],
  ["red",  "red",  "red",  "red",  "red",  ""    ], 
  ["blue", "",     "",     "",     "",     ""    ], 
  ["red", "red",   "",     "",     "",     ""    ]
]

现在我们要在主对角线上翻转这个矩阵。这称为 转置 ,我们使用一个简单的 transpose 函数来执行此操作,产生:

[
  ["red", "blue", "red", "blue", "red", "blue", "red"],
  ["",    "blue", "",    "blue", "red", "",     "red"],
  ["",    "blue", "",    "blue", "red", "",     ""   ],
  ["",    "blue", "",    "blue", "red", "",     ""   ], 
  ["",    "",     "",    "blue", "red", "",     ""   ], 
  ["",    "",     "",    "blue", "",    "",     ""   ]
]

现在剩下要做的唯一一件事就是将这些结果行填充到原始输入的长度,我们通过将 pad 映射到结果和原始输出的长度来再次执行此操作. (在我看来,这是一种相当奇怪的格式,如果不是 class,我会问所有那些尾随的空字符串是否真的有帮助。)

其中,唯一棘手的函数是 group,它找到与数组中初始元素不同的第一个元素的索引,将其拆分为一个新的子数组,然后在结果数组。如果你的课程还没有达到递归,那么你可能应该看看你是否可以用命令式循环而不是递归来做到这一点。

如果您对这些功能有疑问,欢迎在评论中提问。