查找第一个键的有效方法:对象内部的值

时间:2017-09-30 13:36:28

标签: javascript

下面是我需要找到至少一次isSelected: true

的对象
 [
  {
    "isSelected": true,
    "child": [
      {
        "isSelected": true,
        "child": [
          {
            "isSelected": true,
            "child": [
              {
                "isSelected": true
              }
            ]
          }
        ]
      }
    ]
  }
]

上述对象中可以包含 n 元素,每个元素都可以包含 n 子元素,依此类推。对于每个元素,都会有一个isSelected键,其值为“true / false”。

我正在尝试在JavaScript中编写一个函数,如果它发现至少有一个isSelected键出现真值,它将返回true。

使用JSON.stringify()写下面的函数并在其中搜索字符串“isSelected:true”字符串

function hasIsSelected(data){
  return (JSON.stringify(data)).search('"isSelected":true') > -1 ? true: false
}

不确定JSON.stringify()是否对大型对象有效。

尝试在不使用第三方库的情况下在JavaScript中找到解决方案。

3 个答案:

答案 0 :(得分:2)

您可以使用递归算法来检查" isSelected"价值并循环所有孩子:

function hasIsSelected(data) {
    if (data.isSelected) {
        return true;
    }
    if (data.child) {
        for (var i = 0; i < data.child.length; i++) {
            if (hasIsSelected(data.child[i])) {
                return true;
            }
        }
    }
    return false;
}


var json = [...]; // Your value
hasIsSelected(json[0]);

编辑: 好吧,让我们为最坏的情况制作一个非常简单的基准:

function createTestData(depth) {
    var obj = { isSelected: depth === 0 };
    if (depth > 0) {
        obj.child = [createTestData(depth - 1)];
    }
    return obj;
}
var testData = [createTestData(1000)]; // Big object, the "true" value is in the deepest child.


function hasIsSelectedStrinfigy(data){
    return (JSON.stringify(data)).search('"isSelected":true') > -1;
}

function hasIsSelectedRec(data) {
    if (data.isSelected) {
        return true;
    }
    if (data.child) {
        for (var i = 0; i < data.child.length; i++) {
            if (hasIsSelectedRec(data.child[i])) {
                return true;
            }
        }
    }
    return false;
}

// Using NicolaeS's solution 
function hasIsSelectedRecTOC(data) {
    if (data.isSelected === true) {
        return true;
    }
    if (data.child instanceof Array) {
        // stops after the first valid element
        return data.child.some(hasIsSelectedRecTOC);
    }
    return false;
}


// Run tests
function runTest(fun) {
    var t0 = performance.now();
    fun(testData[0]);
    var t1 = performance.now();
    return t1 - t0;
}

console.log("Exec time using stringify : %o", runTest(hasIsSelectedStrinfigy));
console.log("Exec time using recursion : %o", runTest(hasIsSelectedRec));
console.log("Exec time using recursion with TOC : %o", runTest(hasIsSelectedRecTOC));

我的计算机上的结果(每次运行它们都会改变但你明白了):

Exec time using stringify : 6.785000000000004
Exec time using recursion : 0.36999999999999034
Exec time using recursion with TOC : 0.37999999999999545

这是最糟糕的情况。现在有了最好的情况(第一个是选择&#34;真&#34;):

function createTestData(depth) {
    var obj = { isSelected: true }; // isSelected is always true
    if (depth > 0) {
        obj.child = [createTestData(depth - 1)];
    }
    return obj;
}
var testData = [createTestData(1000)];

结果:

Exec time using stringify : 3.980000000000002
Exec time using recursion : 0.040000000000000924
Exec time using recursion with TOC : 0.02499999999999858

答案 1 :(得分:1)

以@Junior的答案为基础 - 递归是最快的方法,但这是使用tail call optimization的更高性能版本:

function hasIsSelected(data) {
  if (data.isSelected === true) {
    return true;
  } else if (data.child instanceof Array) {
    return data.child.some(hasIsSelected); // stops after the first selected element
  } else return false;
}

另一个重要技巧是在找到true后立即停止循环。

答案 2 :(得分:1)

递归将是最好的方法:

const deepSearch = (arr) => {
  return arr.some((v) => {
    if (v.isSelected === true) {
      return true;
    }
    if (Array.isArray(v.child) && v.child.length > 0) {
      return deepSearch(v.child);
    }
    return false;
  });
};

这是jsperf test

已添加Array.isArray(X)X instanceof Array快约3.3倍。这是jsperf test confirming that