多维javascript数组中的直线后代

时间:2012-01-22 05:36:49

标签: javascript arrays algorithm multidimensional-array

我有一个高度嵌套的多维数组,类似于下面的数组。为简单起见,我用json格式表达它:

[
    {
        "Object": "Car",
        "Child": [
            {
                "Object": "Toyota",
                "Child": [
                    {
                        "Object": "Prius"
                    },
                    {
                        "Object": "Yaris"
                    }
                ]
            },
            {
                "Object": "Honda",
                "Child": [
                    {
                        "Object": "Accord"
                    },
                    {
                        "Object": "Civic",
                        "Child": [
                            {
                                "Object": "Sedan"
                            },
                            {
                                "Object": "Coupe"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

如何确定对象是否是另一个对象的直系后代?

例如,“轿车”是“思域”,“本田”和“汽车”的直系后代;但不是“Coupe”,“Accord”,“Toyota”,“Prius”或“Yaris”的直系后裔。

我想做这样的事情:

function Lineal_Descendant(A,B){
    /*do something*/
}

Lineal_Descendant("Sedan","Civic") /*return true*/
Lineal_Descendant("Sedan","Toyota") /*return false*/
Lineal_Descendant("Prius","Honda") /*return false*/
Lineal_Descendant("Yaris","Car") /*return true*/

5 个答案:

答案 0 :(得分:2)

好的,我会试一试:http://jsfiddle.net/nrabinowitz/UJrhK/

function Lineal_Descendant(child, parent) {
    // search in an array of objects
    function walk(array, search) {
        for (var x=0, found; x<array.length; x++) {
            found = visit(array[x], search);
            if (found) return found;
        }
        return false;
    }
    // search an object and its children
    function visit(obj, search) {
        // found search
        return obj.Object === search ? obj :
            // not found, but has children
            obj.Child ? walk(obj.Child, search) :
            // no children
            false; 
    }
    // find parent
    parent = walk(data, parent);
    // find child, converting to boolean
    if (parent) return !!walk(parent.Child || [], child);
}

这可能是一种更优雅的方式,但这会奏效。请注意,您的数据结构中没有任何内容可以强制使用唯一名称,因此如果您在同一级别有两个项目具有相同的Object值,则搜索可能会返回意外结果。

答案 1 :(得分:2)

这是一种怪异的黑客攻击,但你可以使用浏览器DOM模型来做这些事情。将您的数据结构的某种'预先缓存'添加到DOM中并使用querySelectorAll或类似的东西遍历它(jQuery或其他)

参见jsFiddle - http://jsfiddle.net/SxCD6/2/

答案 2 :(得分:1)

这是一个小巧的,自包含的递归函数,可以完成你想要的任务:

function linearDescendant(list, search, ancestor, _parent) {
  var i, item, found = false;

  for (i=0; i<list.length; i++) {
    item = list[i];
    item._parent = _parent;

    if (item.Object == search) {
      while (item._parent && item.Object != ancestor) {
        item = item._parent;
      }
      found = item.Object == ancestor;
    } else if (item.Child) { 
      found = linearDescendant(item.Child, search, ancestor, item);
    }
    if (found) break;
  }
  return found;
}

称之为:

linearDescendant(yourArray, "Sedan", "Civic")  // true
linearDescendant(yourArray, "Sedan", "Toyota") // false
linearDescendant(yourArray, "Prius", "Honda")  // false
linearDescendant(yourArray, "Yaris", "Car")    // true

请注意,该函数会在每个嵌套对象中创建一个_parent属性。一旦找到搜索到的对象,就必须进行祖先检查。

答案 3 :(得分:1)

我最终使用Modified Preorder Tree Traversal的概念。基本上,我使用一个自包含的递归函数循环遍历json对象;并为每个对象分配“左”和“右”值。一旦修改了整个json对象并包含“left”和“right”值,我会比较对象A和B中的“left”和“right”值,看它是否是一个直系后代。

例如,如果对象A是B的直线后代,则A中的“左”值将大于B中的“左”值,而A中的“右”将小于B中的“右”。 / p>

代码:

var data = [{"Object":"Car","Child":[{"Object":"Toyota","Child":[{"Object":"Prius"},{"Object":"Yaris"}]},{"Object":"Honda","Child":[{"Object":"Accord"},{"Object":"Civic","Child":[{"Object":"Sedan"},{"Object":"Coupe"}]}]}]}];

alert(Lineal_Descendant(data,'Sedan','Civic'));  //true
alert(Lineal_Descendant(data,'Sedan','Toyota')); //false
alert(Lineal_Descendant(data,'Prius','Honda'));  //false
alert(Lineal_Descendant(data,'Yaris','Car'));    //true

function Lineal_Descendant(data, A, B){
    var i=1,                  //value to be assigned to "left" or "right" in modified preorder tree traversal
        k=0,                  //value to be assgined to entry index
        aIndex,               //entry index value for object A
        bIndex,               //entry index value for object B
        entry = new Array(),  //entry element
        mpttObj = mptt(data); //modified preorder tree traversal recursive function. Assign "left" and "right" value.

    function mptt(obj) {
        for (var f=0, n=obj.length; f<n; f++) {
            if(obj[f].Object==A) aIndex=k; 
            if(obj[f].Object==B) bIndex=k; 

            obj[f].index=k;
            entry[obj[f].index] = {left:i, right:-1};
            obj[f].left=i;
            //alert(obj[f].Object+','+obj[f].index+','+ obj[f].left);
            k++;
            i++;

            if (obj[f].Child) mptt(obj[f].Child);

            entry[obj[f].index].right = i;
            //alert(obj[f].Object+','+obj[f].index+','+entry[obj[f].index].right);
            obj[f].right=i;
            i++;
        }
        return obj;
    }

    if(entry[aIndex].left>entry[bIndex].left  &&  entry[aIndex].right<entry[bIndex].right) return true;
    else return false;
}

演示:http://jsfiddle.net/bPu2V/

答案 4 :(得分:1)

首先,

请勿使用"Object"作为Object上的密钥。

实际上覆盖本机javascript Object ,这只是一个小错误,它会释放javascript apocalypse。我建议使用name作为替代方案。

其次,这可以通过一个非常简单的递归函数来解决:

var find = function(obj, search){
    // return this object if it matches
    if(obj.name === search)
      return obj;
    // false if it has no children
    if(!obj.hasOwnProperty('Child')) 
      return false;
    for(var i=0,u=obj.Child.length;i<u;i++){
        // recursively check each child
        var foundRecursively = find(obj.Child[i], search);
        if(foundRecursively) // match found! return up the chain
            return foundRecursively; 
    }
    // no match, return up the chain
    return false;
};

var Lineal_Descendant = function(A,B){
    // find the B (the parent) in data, then find A in B.  
    // Negate any object to a boolean and return.
    return !!find(find(data[0],B),A);
};

Lineal_Descendant("Sedan","Civic") // true
Lineal_Descendant("Sedan","Toyota") // false
Lineal_Descendant("Prius","Honda") // false
Lineal_Descendant("Yaris","Car") // true

此解决方案要求数据为具有1个根对象的数组(如示例数据中的OP所示)。也就是说,它很容易适应接受一系列根源开始。