插入/导航嵌套的JavaScript对象/数组

时间:2017-02-06 08:23:23

标签: javascript

我有这些数据:

const items = [
  {
    _id: 0,
    content: 'Item 1 something',
    note: 'Some note for item 1'
  },
  {
    _id: 5,
    content: 'Item 1.1 something',
    note: 'Some note for item 1.1'
  },
  {
    _id: 1,
    content: 'Item 2 something',
    note: 'Some note for item 2',
    subItems: [
      {
        _id: 2,
        parent_id: 1,
        content: 'Sub Item 1 something',
        subItems: [{
          _id: 3,
          parent_id: 2,
          content: 'Sub Sub Item 4'
        }]
      }
    ]
  }
];

使用Javascript,我如何导航/插入树中,在任何一点上我都有树中一个项目的_id。

例如,某些案例场景:

  • 我在_id 3并希望将另一个兄弟插入_id 3
  • 我在_id 2并且想要_id 1 - 我怎么得到_id 1?
  • 我在_id 5,想要去_id 1

如何仅使用_id导航树?

4 个答案:

答案 0 :(得分:1)

您可以迭代数组并测试_id属性是否具有所需值。然后保存节点,父节点或数组的下一个项目。

为了获取父节点,实际的父节点将保存为闭包,并在找到所需的_id时返回。

所有函数都将subItems作为数组进行测试,如果是,则执行subItems上的迭代。

function getNode(array, id) {
    var node;
    array.some(function iter(a) {
        if (a._id === id) {
            node = a;
            return true;
        }
        return Array.isArray(a.subItems) && a.subItems.some(iter);
    });
    return node;
}

function getParent(array, id) {
    var parent ;
    array.some(function iter(p) {
        return function (a) {
            if (a._id === id) {
                parent = p;
                return true;
            }
            return Array.isArray(a.subItems) && a.subItems.some(iter(a));
        };
    }(undefined));
    return parent;
}

function getNextNode(array, id) {
    var node;
    array.some(function iter(a, i, aa) {
        if (a._id === id) {
            node = aa[i + 1];
            return true;
        }
        return Array.isArray(a.subItems) && a.subItems.some(iter);
    });
    return node;
}

var items = [{ _id: 0, content: 'Item 1 something', note: 'Some note for item 1' }, { _id: 5, content: 'Item 1.1 something', note: 'Some note for item 1.1' }, { _id: 1, content: 'Item 2 something', note: 'Some note for item 2', subItems: [{ _id: 2, parent_id: 1, content: 'Sub Item 1 something', subItems: [{ _id: 3, parent_id: 2, content: 'Sub Sub Item 4' }] }] }];

console.log(getNode(items, 3));
console.log(getParent(items, 2));
console.log(getNextNode(items, 5));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:0)

  

使用Javascript,我如何导航/插入树中,在任何一点上我都有树中一个项目的_id。

您必须以递归方式遍历树,并跟踪您的位置和所在位置。

JavaScript引用指向一个方向。除了使用_id 1对对象的引用之外什么都没有,你根本没有连接到它所在的数组。 (它甚至可以存在于同一阵列中的多个阵列或多个位置)。

通常,您需要搜索树(递归是您的朋友)并跟踪您关注的成员的索引。

一旦知道了您正在处理的索引,就可以使用splice

答案 2 :(得分:0)

我已经为这样的问题开发了解决方案。我称之为后视。我的功能看起来:

var backlooker = function(obj) {
  for (key in obj) {
    if (obj[key]._) {
      break;      
    }
    if (obj[key] instanceof Object) {
      obj[key]._ = obj;
      backlooker(obj[key])
    }
  }
  return obj;
}

您必须先改善对象:

items = backlooker(items);

现在你可以这样做:

a = items[2].subItems[0].subItems[0];
c = a._._._._._._._;
c == items; //true

只有一个问题:如果您的对象中已经有名为_的密钥,代码将无法正常运行(我认为这种情况非常罕见,但可能)。

答案 3 :(得分:0)

它并不像“导航”那么简单。以下函数将循环遍历对象,并提供可用于实现所需内容的内容..如名称,值,类型,子项数和深度。

还会在下面查看您案例的具体示例

主要功能

您只需将其称为:loopThrough(items)并观看您的控制台以获取详细信息。

function loopThrough(obj, depth) {
    if (typeof(depth) === "undefined") {
        depth = 0; // depth 0 means the "root" of your object
    } else {
        depth++ // increase depth if exist... depth 1 means a property of an object on depth 0
    }
    for (keyName in obj) {
        let thisObj = obj[keyName] //value of this object
        let type = thisObj.constructor.name // type: Array, Object, String, Number or Function...
        if (type === "Object" || type === "Array") { // to check if this object "have children" to loop through
            let childCount = type === "Object" ? Object.keys(thisObj).length : thisObj.length
            console.group(depth + " (" + type + ") " + keyName + " : " + childCount) // starts a collapsable group called: depth, type and key
            loopThrough(thisObj, depth) //loop through the child object
            console.groupEnd() // closes the group
        } else { // doesn't have children (a String, Number or Function)
            console.log(depth + " (" + type + ") " + keyName + " : " + thisObj) // types: depth, type key and value
        }
    }
}

实施例

这是一个以_id:3为目标的示例,在此示例中,我向所需密钥添加了一个兄弟。

loopThrough(items, "_id", 3)

function loopThrough(obj, wantedKey = "", wantedValue = "", depth) {
    if (typeof(depth) === "undefined") {
        depth = 0;
    } else {
        depth++
    }
    for (keyName in obj) {
        let thisObj = obj[keyName]
        let type = thisObj.constructor.name
        if (type === "Object" || type === "Array") {
            let childCount = type === "Object" ? Object.keys(thisObj).length : thisObj.length
            loopThrough(thisObj, wantedKey, wantedValue, depth)
        }
        if (keyName === wantedKey && thisObj === wantedValue){
          siblings = Object.keys(obj)
          console.log('%c Hello!, I am ' + wantedKey +":"+ wantedValue, 'color: green');
          console.log('%c I have '+ siblings.length + " siblings: " + siblings.toString(), 'color: green');
          console.log("%c adding a new sibling...", 'color: grey')
          obj["new_sibling"] = "new_sibling_value" // add a sibling to _id 3
          siblings = Object.keys(obj)
          console.log('%c now I have '+ siblings.length + " siblings: " + siblings.toString(), 'color: green');
          console.log('%c I am at depth ' + depth, 'color: blue');
          console.log('%c it should be simple to find a way to get my parent _id at depth ' + (depth - 1)  , 'color: blue');ParentID
          console.log(JSON.stringify(items, null, 4));
        }
    }
}
  • 对于您的第二个请求,您必须调整函数以存储所需密钥的深度,并通过调用该函数或创建另一个函数在_id查找其父depth - 1

  • 对于第三个请求,您可以count++密钥,一旦找到wantedKey,您就可以存储计数并再次循环查找count - 1又名以前的兄弟或count + 1又名下一个兄弟

正如你所看到的,这不是一项简单的任务,但它完全有可能带来一些创造力,祝你好运。