New*_*his 50 javascript iteration
我正在尝试遍历嵌套对象以检索由字符串标识的特定对象.在下面的示例对象中,标识符字符串是"label"属性.我无法绕过如何遍历树以返回适当的对象.任何帮助或建议将不胜感激.
var cars = {
label: 'Autos',
subs: [
{
label: 'SUVs',
subs: []
},
{
label: 'Trucks',
subs: [
{
label: '2 Wheel Drive',
subs: []
},
{
label: '4 Wheel Drive',
subs: [
{
label: 'Ford',
subs: []
},
{
label: 'Chevrolet',
subs: []
}
]
}
]
},
{
label: 'Sedan',
subs: []
}
]
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*son 43
您可以创建这样的递归函数来对cars对象进行深度优先遍历.
var findObjectByLabel = function(obj, label) {
if(obj.label === label) { return obj; }
for(var i in obj) {
if(obj.hasOwnProperty(i)){
var foundLabel = findObjectByLabel(obj[i], label);
if(foundLabel) { return foundLabel; }
}
}
return null;
};
Run Code Online (Sandbox Code Playgroud)
这可以这样称呼
findObjectByLabel(car, "Chevrolet");
Run Code Online (Sandbox Code Playgroud)
Men*_*ris 16
如果你想深深迭代到一个复杂的(嵌套)对象为每个键和值,你可以这样做使用Object.keys() ,递归:
const iterate = (obj) => {
Object.keys(obj).forEach(key => {
console.log(`key: ${key}, value: ${obj[key]}`)
if (typeof obj[key] === 'object') {
iterate(obj[key])
}
})
}
Run Code Online (Sandbox Code Playgroud)
Jac*_*fin 13
function forEachNested(O, f, cur){
O = [ O ]; // ensure that f is called with the top-level object
while (O.length) // keep on processing the top item on the stack
if(
!f( cur = O.pop() ) && // do not spider down if `f` returns true
cur instanceof Object && // ensure cur is an object, but not null
[Object, Array].includes(cur.constructor) //limit search to [] and {}
) O.push.apply(O, Object.values(cur)); //search all values deeper inside
}
Run Code Online (Sandbox Code Playgroud)
要使用上述函数,请将数组作为第一个参数传递,将回调函数作为第二个参数传递。回调函数在调用时将接收 1 个参数:正在迭代的当前项目。
function forEachNested(O, f, cur){
O = [ O ]; // ensure that f is called with the top-level object
while (O.length) // keep on processing the top item on the stack
if(
!f( cur = O.pop() ) && // do not spider down if `f` returns true
cur instanceof Object && // ensure cur is an object, but not null
[Object, Array].includes(cur.constructor) //limit search to [] and {}
) O.push.apply(O, Object.values(cur)); //search all values deeper inside
}
Run Code Online (Sandbox Code Playgroud)
“作弊”替代方案可能是JSON.stringify用于迭代。但是,JSON.stringify将调用toString它传递的每个对象的方法,如果您对toString.
function forEachNested(O, f, v){
typeof O === "function" ? O(v) : JSON.stringify(O,forEachNested.bind(0,f));
return v; // so that JSON.stringify keeps on recursing
}
Run Code Online (Sandbox Code Playgroud)
(function(){"use strict";
var cars = {"label":"Autos","subs":[{"label":"SUVs","subs":[]},{"label":"Trucks","subs":[{"label":"2 Wheel Drive","subs":[]},{"label":"4 Wheel Drive","subs":[{"label":"Ford","subs":[]},{"label":"Chevrolet","subs":[]}]}]},{"label":"Sedan","subs":[]}]};
var lookForCar = prompt("enter the name of the car you are looking for (e.g. 'Ford')") || 'Ford';
lookForCar = lookForCar.replace(/[^ \w]/g, ""); // incaseif the user put quotes or something around their input
lookForCar = lookForCar.toLowerCase();
var foundObject = null;
forEachNested(cars, function(currentValue){
if(currentValue.constructor === Object &&
currentValue.label.toLowerCase() === lookForCar) {
foundObject = currentValue;
}
});
if (foundObject !== null) {
console.log("Found the object: " + JSON.stringify(foundObject, null, "\t"));
} else {
console.log('Nothing found with a label of "' + lookForCar + '" :(');
}
function forEachNested(O, f, cur){
O = [ O ]; // ensure that f is called with the top-level object
while (O.length) // keep on processing the top item on the stack
if(
!f( cur = O.pop() ) && // do not spider down if `f` returns true
cur instanceof Object && // ensure cur is an object, but not null
[Object, Array].includes(cur.constructor) //limit search to [] and {}
) O.push.apply(O, Object.values(cur)); //search all values deeper inside
}
})();Run Code Online (Sandbox Code Playgroud)
然而,虽然上述方法对于演示目的可能有用,Object.values但 Internet Explorer 不支持,并且代码中有许多非常糟糕的地方:
Array.prototype.push和Array.prototype.pop[第 5 行和第 8 行],Object.values[第 8 行]返回的数组,window.Object或window.Object.values[第 9 行],下面是一个快得多的版本,应该比任何其他解决方案都快得多。下面的解决方案修复了上面列出的所有性能问题。然而,它以一种截然不同的方式进行迭代:它首先迭代所有数组,然后迭代所有对象。它继续迭代其当前类型,直到完全耗尽,包括正在迭代的当前风味的当前列表中的迭代子值。然后,该函数迭代所有其他类型。通过在切换之前迭代直到耗尽,迭代循环变得比其他方式更热并且迭代得更快。这个方法还有一个额外的好处:对每个值调用的回调函数传递了第二个参数。第二个参数是从返回的数组Object.values 在父哈希对象或父数组本身上调用。
var getValues = Object.values; // localize
var type_toString = Object.prototype.toString;
function forEachNested(objectIn, functionOnEach){
"use strict";
functionOnEach( objectIn );
// for iterating arbitrary objects:
var allLists = [ ];
if (type_toString.call( objectIn ) === '[object Object]')
allLists.push( getValues(objectIn) );
var allListsSize = allLists.length|0; // the length of allLists
var indexLists = 0;
// for iterating arrays:
var allArray = [ ];
if (type_toString.call( objectIn ) === '[object Array]')
allArray.push( objectIn );
var allArraySize = allArray.length|0; // the length of allArray
var indexArray = 0;
do {
// keep cycling back and forth between objects and arrays
for ( ; indexArray < allArraySize; indexArray=indexArray+1|0) {
var currentArray = allArray[indexArray];
var currentLength = currentArray.length;
for (var curI=0; curI < currentLength; curI=curI+1|0) {
var arrayItemInner = currentArray[curI];
if (arrayItemInner === undefined &&
!currentArray.hasOwnProperty(arrayItemInner)) {
continue; // the value at this position doesn't exist!
}
functionOnEach(arrayItemInner, currentArray);
if (typeof arrayItemInner === 'object') {
var typeTag = type_toString.call( arrayItemInner );
if (typeTag === '[object Object]') {
// Array.prototype.push returns the new length
allListsSize=allLists.push( getValues(arrayItemInner) );
} else if (typeTag === '[object Array]') {
allArraySize=allArray.push( arrayItemInner );
}
}
}
allArray[indexArray] = null; // free up memory to reduce overhead
}
for ( ; indexLists < allListsSize; indexLists=indexLists+1|0) {
var currentList = allLists[indexLists];
var currentLength = currentList.length;
for (var curI=0; curI < currentLength; curI=curI+1|0) {
var listItemInner = currentList[curI];
functionOnEach(listItemInner, currentList);
if (typeof listItemInner === 'object') {
var typeTag = type_toString.call( listItemInner );
if (typeTag === '[object Object]') {
// Array.prototype.push returns the new length
allListsSize=allLists.push( getValues(listItemInner) );
} else if (typeTag === '[object Array]') {
allArraySize=allArray.push( listItemInner );
}
}
}
allLists[indexLists] = null; // free up memory to reduce overhead
}
} while (indexLists < allListsSize || indexArray < allArraySize);
}
Run Code Online (Sandbox Code Playgroud)
function forEachNested(O, f, v){
typeof O === "function" ? O(v) : JSON.stringify(O,forEachNested.bind(0,f));
return v; // so that JSON.stringify keeps on recursing
}
Run Code Online (Sandbox Code Playgroud)
如果您在循环引用方面遇到问题(例如,对象 A 的值是对象 A 本身,例如对象 A 包含自身),或者您只需要键,那么可以使用以下较慢的解决方案。
function forEachNested(O, f){
O = Object.entries(O);
var cur;
function applyToEach(x){return cur[1][x[0]] === x[1]}
while (O.length){
cur = O.pop();
f(cur[0], cur[1]);
if (typeof cur[1] === 'object' && cur[1].constructor === Object &&
!O.some(applyToEach))
O.push.apply(O, Object.entries(cur[1]));
}
}
Run Code Online (Sandbox Code Playgroud)
因为这些方法不使用任何类型的递归,所以这些函数非常适合可能有数千个深度级别的领域。堆栈限制因浏览器而异,因此在 Javascript 中递归到未知深度并不是很明智。
| 归档时间: |
|
| 查看次数: |
78547 次 |
| 最近记录: |