【问题标题】:What is the fastest way of finding if object has a value (multidimensional object)查找对象是否具有值(多维对象)的最快方法是什么
【发布时间】:2026-02-11 10:45:01
【问题描述】:

我有一个具有 3 级深度的多维对象。如果第三级对象具有给定值,我正在尝试。我想到的是for循环遍历每个级别并使用(Object.values(obj).indexOf('red') > -1)进行检查,但据我了解,for循环是一种缓慢的方式。

例如,在下面的对象中,检查任何最内部的值是否具有red 值并返回布尔值的最快方法是什么?

myObj: {
   user1: {
      apples: {
        1: "red",
        2: "green",
        3: "black"
      },
      cherry: {
        2: "green"
        4: "dark"
      }
   },

   user2: {
     orange: {
        1: "orange"
     }
   }
}

【问题讨论】:

  • 嗨,为什么不用myObj.user1.apples 搜索一下呢?
  • for-looping 和使用 Object.values 一样慢。不,没有比线性搜索更好的方法了,除非你建立一个查找结构(只有在你需要进行多次查找时才会变得高效)。
  • @ankabout 这只是一个伪示例。抱歉,它太假了。

标签: javascript object ecmascript-6


【解决方案1】:

这是一种递归方法,使用Oject.values()Array.some() 来检查对象中是否存在值:

const obj = {"user1":{"apples":{"1":"red","2":"green","3":"black"},"cherry":{"2":"green","4":"dark"}},"user2":{"orange":{"1":"orange"}}};

const findValue = (o, val) => Object.values(o)
  .some((v) => v && typeof(v) === 'object' ? findValue(v, val) : (v === val));
  
console.log(findValue(obj, 'red'));
console.log(findValue(obj, 'gold'));

【讨论】:

  • 谢谢。我总是想念旧的null 是一个对象:)
  • 您为什么认为这是“最快的方式”,OP 认为“慢”的嵌套 for 循环有什么优势?
  • 感谢您的意见。我都在看,但实际上哪个更好?我非常喜欢这种方法,仅仅是因为它的行数更少
  • @senty 在“两者”?我是什么,切碎的肝脏?而且仅仅因为 sn-p 更短,并不一定会以任何方式使其更有效。
  • @senty 我可能有偏见,但是这两个答案都使用Object.values() 的事实意味着它们实际上是广度优先而不是深度优先,而使用for...in 的我的实际上 是深度优先的,因为它迭代lazily,因此将首先到达最深层,并且 没有尽可能多的函数调用这些,也会产生更多的开销。
【解决方案2】:

您可以使用depth-first search 并查找嵌套对象。

function contains(object, value) {
    return Object.values(object).some(
        v => v && typeof v === 'object'
            ? contains(v, value) :
            v === value
    );
}

var myObj = { user1: { apples: { 1: "red", 2: "green", 3: "black" }, cherry: { 2: "green", 4: "dark" } }, user2: { orange: { 1: "orange" } } };

console.log(contains(myObj, 'red'));
console.log(contains(myObj, 42));

另一种解决方案可能是使用堆栈执行线性搜索而无需递归。

这是breadth-first-search

function contains(object, value) {
    var stack = Object.values(object),
        v;

    while (stack.length) {
        v = stack.shift();
        if (v && typeof v === 'object') {
            stack.push(...Object.values(v));
            continue;
        }
        if (v === value) {
            return true;
        }
    }
    return false;
}

var myObj = { user1: { apples: { 1: "red", 2: "green", 3: "black" }, cherry: { 2: "green", 4: "dark" } }, user2: { orange: { 1: "orange" } } };

console.log(contains(myObj, 'red'));
console.log(contains(myObj, 42));
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 您为什么认为这是“最快的方式”,OP 认为“慢”的嵌套 for 循环有什么优势?
  • @PatrickRoberts,对不起,恕我直言,这是广度优先搜索,因为递归调用首先查看孩子,然后查看邻居,即使首先收集邻居,但未检查。
【解决方案3】:

使用递归深度优先函数来遍历键,然后在最深的层次上,只返回true。一个“陷阱”是确保字符串在迭代时不返回单个字符串,因为这只会无限递归。

function hasKey(object, depth = 0) {
  if (depth === 0) {
    return true;
  }

  for (const key in Object(object)) {
    const value = object[key];
    // prevent nested checks of characters in strings
    if (typeof value !== 'string' || value.length !== 1 || typeof object !== 'string') {
      if (hasKey(value, depth - 1)) {
        return true;
      }
    }
  }

  return false;
}

let myObj = {"user1":{"apples":{"1":"red","2":"green","3":"black"},"cherry":{"2":"green","4":"dark"}},"user2":{"orange":{"1":"orange"}}};

// has keys at depth 3
console.log(hasKey(myObj, 3));
// does not have keys at depth 4
console.log(hasKey(myObj, 4));

虽然此答案的行数可能更长,但它确实会在每个深度迭代键,而不是将所有Object.values() 缓冲到每个深度的数组中,这在技术上使其他答案无法获得“深度优先”的方法,因为缓冲会导致“广度优先”的行为。

【讨论】: