如何发现多维数组中的模式并将数据分解为可用类型,例如“地图”或“集合”

时间:2019-06-24 17:54:09

标签: javascript arrays multidimensional-array

我想这是一个开放性的问题,不是一个完全具体的问题,但是我认为这是一个很好的例子,说明我们的大脑可以轻松地完成哪些工作,可能很难编写代码。一个解决方案很酷,但是我真的对您的未来方法更感兴趣

这个特殊问题来自CodeSignal的图论部分,并要求我们编写一个函数,该函数根据给定的邻接矩阵(对于本示例而言不重要)来确定图是否类似于领结

您可以想象一个中心顶点,其中有两对折断的“道路”(或度数),每对在其其他两个顶点之间共享一个排他的“道路”。

我已经解决了其他几个问题,但这是一组新的包含特定形状的问题,并且更容易发现传递输入的模式。我已经使用了大量的Array.prototype方法来构建和转换多维数组。 每个问题都花了我相当长的时间。我真的很难找到一种有效的方法来处理这些数据。

以下是测试用例的“道路”(或度数)列表。(为方便起见,我将邻接矩阵变成了道路阵列。)每个数字代表一个节点,或者一个顶点(如果容易的话,永远只有五个)...

[ [ '0', '1' ],
  [ '0', '2' ],
  [ '1', '0' ],
  [ '1', '2' ],
  [ '2', '0' ],
  [ '2', '1' ],
  [ '2', '3' ],
  [ '2', '4' ],
  [ '3', '2' ],
  [ '3', '4' ],
  [ '4', '2' ],
  [ '4', '3' ] ]

(注意:中心顶点将不在数组中指定,这只是一个示例。)

即使没有图论训练,我们也可以在几秒钟内说出这是有效的“领结”。

注意:有些道路是重复的,但我是故意这样做的...我认为如果更容易看清,那么会更容易编码。

我们想从这样的数组中读取并确定(返回true)道路是否形成领结。 |> <|

我之所以问是因为我敢打赌,有一些我不知道要考虑的JavaScript功能。我知道地图和集合是什么,我认为地图可能会有所帮助,但是我有点缺乏编码经验。预先谢谢你!

1 个答案:

答案 0 :(得分:0)

寻找有效地完成这类事情的算法可能非常棘手-我不一定能在那方面为您提供建议,但是我可以提供一些编码建议。

1)转换数组->对象

普通的JavaScript objectMap可能是图形对象的有用数据类型。它们实际上是相似的(略有不同)数据类型,它们根据键值对存储事物。一种策略:您可以将每个节点设置为键,将一组连接的节点设置为值。对于此信息,这感觉像是一个更有用的结构。像这样:

/**
 * Convert array of arrays into object
 * where {key=node, val=[array of connected nodes]}
 */
function arrayToObj(roadsArr) {
  // start with empty object
  var obj = {};

  // iterate over each pair in roads array
  // initialize new {key: [val]} entry if none exists
  // otherwise add to existing list of values
  roadsArr.forEach(function(pair) {
    var key = pair[0];
    var val = pair[1];
    if (obj[key] === undefined) {
      obj[key] = [val];
    } else {
      obj[key].push(val);
    }
  });
  return obj;
}


roadsArr = [
  ["0", "1"],
  ["0", "2"],
  ["1", "0"],
  ["1", "2"],
  ["2", "0"],
  ["2", "1"],
  ["2", "3"],
  ["2", "4"],
  ["3", "2"],
  ["3", "4"],
  ["4", "2"],
  ["4", "3"]
];

var roadsObj = arrayToObj(roadsArr);
console.log(roadsObj);

2)测试图条件

接下来,我会考虑需要检查的条件,以验证是否为领结并一次对其进行测试。

五个节点

您提到应该恰好有五个节点:我们可以通过检查正好有五个键来对其进行测试。

/**
 * Check there are exactly five nodes
 * Returns true if 5 keys in roadsObj, false otherwise
 */
function hasFiveNodes(roadsObj) {
  var keys = Object.keys(roadsObj); // -> [0, 1, 2, 3, 4]
  return keys.length === 5;
}

连接数

您提到一个节点应具有四个连接,而其他节点则应具有两个连接。这是一种检查方法:

/**
 * Check that each node has two connections, except one node with 4
 */
function hasValidNumConnections(roadsObj) {
  // extract array of values from object
  var valuesArr = Object.values(roadsObj); // -> [[0,1], [0,2] ... [2,3]]

  // map list of values into list of lengths
  var lenArr = valuesArr.map(x => x.length); // -> [2, 2, 4, 2, 2]

  // sort array of lengths
  var sortedLenArr = lenArr.sort(); // -> [2, 2, 2, 2, 4]

  // compare to desired string (because comparing arrays is tricky in JS)
  return sortedLenArr.toString() === "2,2,2,2,4";
}

其他条件?

您可能还必须检查其他一些条件-例如,您可能不仅要检查每个节点有多少连接,还要检查哪些连接以确保领结结构。 / p>

3)放在一起

将每个条件检查分离为自己的功能可能不是最有效的策略,但是如果效率不是至关重要的,则它提供了一个很好的结构来思考问题并继续构建您的解决方案。总之,它看起来可能像这样:

// ---------- helper function ----------

/**
 * Convert array of arrays into object
 * where {key=node, val=[array of connected nodes]}
 */
function arrayToObj(roadsArr) {
  var obj = {};
  roadsArr.forEach(function(pair) {
    var key = pair[0];
    var val = pair[1];
    if (obj[key] === undefined) {
      obj[key] = [val];
    } else {
      obj[key].push(val);
    }
  });
  return obj;
}

// ---------- validator functions ----------

/**
 * Check there are exactly five nodes
 * Returns true if 5 keys in roadsObj, false otherwise
 */
function hasFiveNodes(roadsObj) {
  var keys = Object.keys(roadsObj); // -> [0, 1, 2, 3, 4]
  return keys.length === 5;
}

/**
 * Check that each node has two connections, except one node with 4
 */
function hasValidNumConnections(roadsObj) {
  var valuesArr = Object.values(roadsObj); // -> [[0,1], [0,2] ... [2,3]]
  var lenArr = valuesArr.map(x => x.length);
  var sortedLenArr = lenArr.sort();
  return sortedLenArr.toString() === "2,2,2,2,4";
}

// ---------- main function ----------

/**
 * Check if given array represents a bowtie graph.
 */
function isBowtie(roadsArr) {
  // convert array to object
  var roadsObj = arrayToObj(roadsArr);

  // has exactly 5 nodes?
  if (!hasFiveNodes(roadsObj)) {
    return false;
  }
  console.log("> has 5 nodes");

  // has one node with 4 connections
  if (!hasValidNumConnections(roadsObj)) {
    return false;
  }
  console.log("> has valid number connections");

  // other checks??
  // ... insert here

  // if all pass, return true
  return true;
}

// ---------- testing ----------

roadsArr = [
  ["0", "1"],
  ["0", "2"],
  ["1", "0"],
  ["1", "2"],
  ["2", "0"],
  ["2", "1"],
  ["2", "3"],
  ["2", "4"],
  ["3", "2"],
  ["3", "4"],
  ["4", "2"],
  ["4", "3"]
];

var result = isBowtie(roadsArr);
console.log(result);