根据特定规则获取自定义数组列表的层次结构顺序

时间:2017-01-17 05:18:21

标签: javascript jquery arrays algorithm

我想从下面的数组列表中获取层次结构顺序。

var data = [
   ['','dog'],
   ['dog','cat'],
   ['dog','fish'],
   ['dog','ark'],
   ['dog','folder'],
   ['cat','blue'],
   ['cat','pencil'],
   ['cat','mouse'],
   ['fish','stencil'],
   ['fish','bread'],
   ['fish','milk'],
   ['fish','love'],
   ['mouse','tv'],
   ['mouse','oil'],
   ['mouse','car'],
   ['milk','dough'],
   ['milk','butter'],
   ['car','truck']
];

计算'的方法这是从

的第一个数组开始
['','dog']

注意:我会将0索引('')称为' parent'和1个指数(' dog')作为'孩子'

所以我们想找到那些拥有“狗”的阵列。作为父母,然后检查这些数组,看看他们的孩子是否有父母,如果没有,继续下一个。 (真的希望这是有道理的)

以下是我上述数据集的订单结果。

var result = ['dog', 'cat', 'blue', 'pencil', 'mouse', 'tv', 'oil', 'car', 'truck', 'fish', 'stencil', 'bread', 'milk', 'dough', 'butter', 'love', 'ark', 'folder'];

我尝试使用一些非常糟糕的while循环和.filters()来获取包含child作为父索引的数组,但是失败了。

如果任何人都可以对此有所了解或者返回最终结果的方法,我会非常感激,因为我无法手动解决这个问题。

1 个答案:

答案 0 :(得分:2)

我认为,这是你的算法。

  1. 将源数组转换为嵌套对象,该对象使用pass-by-reference有效地关联父项和子项。
  2. 这是ES6的实现:

    function pairsToIndex(pairs) {
        return pairs.reduce((index, pair, i, list) => {
            let [ parent , child ] = pair;
    
            let parent_exists = index.hasOwnProperty(parent);
            let child_exists = index.hasOwnProperty(child);
    
            if(!parent_exists) {
                index[parent] = { key: parent , children: [] };
            }
    
            if(!child_exists) {
                index[child] =  { key: child  , children: [] };
            }
    
            // now, ensure that parent-child relationship is captured
            let rel_captured = Boolean( index[parent].children.find((c) => c.key === child) );
    
            if(!rel_captured) {
                index[parent].children.push( index[child] );
            }
    
            return index;
        }, {});
    }
    
    let data = [
        ['','dog'],
        ['dog','cat'],
        ['dog','fish'],
        ['dog','ark'],
        ['dog','folder'],
        ['cat','blue'],
        ['cat','pencil'],
        ['cat','mouse'],
        ['fish','stencil'],
        ['fish','bread'],
        ['fish','milk'],
        ['fish','love'],
        ['mouse','tv'],
        ['mouse','oil'],
        ['mouse','car'],
        ['milk','dough'],
        ['milk','butter'],
        ['car','truck']
    ];
    
    let x = pairsToIndex(data);
    console.log(x);
    

    在浏览器的开发控制台中运行该代码。当您浏览对象x时,您会注意到每个"孩子"就像x的另一个顶级属性的符号链接一样。实际上,每个孩子都会#34;是该对象中其他位置的门户。这种传递参考的使用为我们设定了第2步......

    1. 通过以深度优先模式递归遍历该对象并返回每个节点的key prop来序列化该对象。
    2. 所以,这里有一个简短的说明:

      function listNode(node) {
          return Array.prototype.concat.apply( [node.key] , node.children.map(listNode) );
      }
      
      let out = listNode(x['']); // choosing the entry point to the hierarchy
      console.log(out);
      

      请注意,我必须使用apply来避免创建一堆嵌套的1元素数组(即使它们会被正确排序)。这可以用_.flatten之类的东西解决,但是这种情况下,了解一点语言可以避免对整个图书馆的需求。

      另请注意,listNode在技术上对层次结构的子树进行操作。我告诉它从" root"开始您建议的节点在原始数据集中由空字符串标识。但是,您可以要求它通过将树的子集传递给不同的起始点来序列化树的子集,例如, listNode( x['cat'] )listNode( x['fish'] )

      最后,这个算法是无限递归的。如果您向其提供非常大的数据集,浏览器将暂停此脚本。其他JS环境(如nodejs或react-native)不会这样做。

      此时,out是一个数组,按照您希望的顺序列出原始data数组中的每个值。