如何为以后的迭代创建递归对象树数组?

时间:2016-07-11 15:09:44

标签: javascript arrays dictionary recursion key

我的问题稍微similar to this one

所以,说我有这样一个对象:

var obj = {
  'a': {
    'b': {
      'c': 1,
      'd': 2
    },
    'e': 3
  },
  'f': 4,
  'g': 5
};

我想通过一个函数运行它并创建一个类似于这样的数组:

var arr =
  'a',
  'a.b',
  'a.b.c',
  'a.b.d',
  'a.e',
  'f',
  'g'
];

该数组的目的是让我以后可以以完全相同的方式循环使用相同分层格式的对象。我不确定如何做这一步。

因此,在objarr的情况下,它会使用for循环来访问obj中的所有键值对。据我所知,你无法访问这样的嵌套属性:obj['a.b.c'],所以我不确定如何做到这一点。

澄清编辑:

创建此数组后,我想知道如何使用它以数组描述的方式循环相同格式的对象。例如

function iterateAnotherObjectWithSameFormat(aObj) {
  for (var i = 0; i < arr.length; i++) {
    // access aObj['a'], then aObj['a.b'], then aObj['a.b.c'], etc..
  }
}

2 个答案:

答案 0 :(得分:2)

您可以采用递归方法,其中单个调用迭代属性并将键放入数组中。使用实际值再次调用该函数,使用访问键调用该数组,直到找不到其他对象。

function flatKeys(object) {

    function iter(part, keys) {
        Object.keys(part).forEach(function (k) {
            var allKeys = keys.concat(k);
            flat.push(allKeys.join('.'));
            if (part[k] !== null && !Array.isArray(part[k]) && typeof part[k] === 'object') {
                iter(part[k], allKeys);
            }
        });
    }

    var flat = [];
    iter(object, []);
    return flat;
}

function getValue(object, path) {
    return path.split('.').reduce(function (r, a) {
        return (r || {})[a];
    }, object);
}

var object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4, 'g': 5 },
    keys = flatKeys(object)

console.log(keys);
keys.forEach(function (a) {
    console.log(a, getValue(object, a));
});

扁平物体

function flatKeys(object) {

    function iter(part, keys) {
        Object.keys(part).forEach(function (k) {
            var allKeys = keys.concat(k);
            flat[keys.concat(k).join('.')] = part[k];
            if (part[k] !== null && !Array.isArray(part[k]) && typeof part[k] === 'object') {
                iter(part[k], keys.concat(k));
            }
        });
    }

    var flat = {};
    iter(object, []);
    return flat;
}

var object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4, 'g': 5 },
    flat = flatKeys(object);

console.log(flat);

答案 1 :(得分:0)

遇到的每个属性名称都将以属性链上的键为前缀并添加到数组中。

继续搜索,直到处理完所有嵌套对象。

&#13;
&#13;
function findKeys(object, prefix) {
  prefix = (typeof prefix !== 'undefined') ? (prefix + '.') : '';

  var keys = [];
  Object.keys(object).forEach(function(key) {
    keys.push(prefix + key);
    if (typeof object[key] === 'object' && object[key] !== null && !Array.isArray(object[key]))
      keys = keys.concat(findKeys(object[key], prefix + key));
  });
  return keys;
};


console.log( findKeys({ 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4, 'g': 5 }) );
&#13;
&#13;
&#13;

如果要访问具有变量名称的对象属性,则必须使用括号表示法。

但是您无法使用字符串访问嵌套属性。无论点是什么,您的字符串都被视为普通的属性名称。

您需要自己解析字符串。幸运的是,使用reduce非常简单。

var object = {
  'a': {
    'b': 5
  },
  'a.b': 10
};

var property = 'a.b';
console.log(object[property]);                            // 10
console.log(getNestedPropertyValue(object, property));    // 5

function getNestedPropertyValue(object, nestedProperty) {
  return nestedProperty.split('.').reduce(function(object, property) {
    return object[property];
  }, object);
}

这是一个完整的例子:

&#13;
&#13;
function findKeys(object, prefix) {
  prefix = (typeof prefix !== 'undefined') ? (prefix + '.') : '';

  var keys = [];
  Object.keys(object).forEach(function(key) {
    keys.push(prefix + key);
    if (typeof object[key] === 'object' && object[key] !== null && !Array.isArray(object[key]))
      keys = keys.concat(findKeys(object[key], prefix + key));
  });
  return keys;
};


var obj1 = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4, 'g': 5 };

var obj2 = { 'a': { 'b': { 'c': 111, 'd': 222 }, 'e': 333 }, 'f': 444, 'g': 555 };

var arr = findKeys(obj1);


var iterateAnotherObjectWithSameFormat = (function() {

  function getNestedPropertyValue(object, nestedProperty) {
    return nestedProperty.split('.').reduce(function(object, property) {
      return object[property];
    }, object);
  }

  return function(object, keys, callback) {
    keys.forEach(function(key) {
      callback(getNestedPropertyValue(object, key));
    });
  };

}());

iterateAnotherObjectWithSameFormat(obj2, arr, function(value) {
  console.log(value);
});
&#13;
&#13;
&#13;