【问题标题】:Return true if value matches any value including nested object value如果值匹配任何值,包括嵌套对象值,则返回 true
【发布时间】:2017-03-08 03:58:49
【问题描述】:

我有一个嵌套对象,其中包含:

var obj = {
  id: 1,
  name: 'Stephen',
  age: 18,
  department: {
    id: 1,
    text: 'Operations'
  }
}

因此,如果我有一个字符串或一个值数组与集合中的任何值(包括嵌套对象值)匹配,它将返回 true。我曾尝试使用 lodash 的 _.includes,但我不知道如何遍历嵌套对象。

_.includes(obj.department, 'Operations')

我想做的更像是

_.includes(obj, ['Stephen', 'Operations']) // 返回真

【问题讨论】:

  • 你在问什么?

标签: javascript object lodash


【解决方案1】:

Array#some 使用递归来检查值是否存在。当谓词的结果为true 时,Array#some 立即返回。

var obj = {
  id: 1,
  name: 'Stephen',
  age: 18,
  department: {
    id: 1,
    text: 'Operations'
  }
}

function recursiveIncludes(obj) {
  var values = [].slice.call(arguments, 1);
  
  return Object.keys(obj).some(function(key) {
    var current = obj[key];
 
    if(values.indexOf(current) !== -1) {
      return true;
    }
    
    if(typeof current === 'object' && current !== null) {
      return recursiveIncludes.apply(null, [current].concat(values));
    }
    
    return false;
  });
}

console.log('Operations: ', recursiveIncludes(obj, 'Operations'));
console.log('Moses, Stephen: ', recursiveIncludes(obj, 'Moses', 'Stephen'));
console.log('Moses, 58: ', recursiveIncludes(obj, 'Moses', 58));

【讨论】:

    【解决方案2】:

    这是一种递归方法。它将对象的所有属性(叶属性)提取到一个数组中。然后你可以调用 _.includes() 。

    var obj = {
      id: 1,
      name: 'Stephen',
      age: 18,
      department: {
        id: 1,
        text: 'Operations'
      }
    }
    
    function objToArray(obj) {
        var result = [];
        for (const prop in obj) {
            const value = obj[prop];
            if (typeof value === 'object') {
                result = result.concat(toArray(value)); 
            }
            else {
                result.push(value);
            }
        }
        return result;
    }
    
    _.includes(objToArray(obj), ['Stephen', 'Operations'])
    

    【讨论】:

      【解决方案3】:

      给定一个字符串数组,这将检查并查看该属性是否递归存在。

      var obj = {
        id: 1,
        name: 'Stephen',
        age: 18,
        department: {
          id: 1,
          text: 'Operations'
        }
      }
      
      function hasValues(obj, props)
      {
        var keys = Object.keys(obj);
        for(var i = 0; i < keys.length; i++){
          var item = obj[keys[i]];
          // If the item is a string or number, do a comparison
          if(typeof item === "string" || typeof item === "number"){
            var idx = props.indexOf(item);
            if(idx >= 0) props.splice(idx, 1);
          // If it's an object then search the object recursively
          } else if(typeof item === "object"){
            hasValues(item, props);
          }
        }
      
        return props.length === 0;
      }
      
      console.log(hasValues(obj, ['Stephen', 'Operations']))
      console.log(hasValues(obj, [18, 1]))
      console.log(hasValues(obj, [18, '13lkj4']))

      【讨论】:

        【解决方案4】:

        您可以使用flatMap 作为一种机制,在flatMap 回调函数中使用map 递归地平展所有从递归获取的值。得到所有的值后,我们用difference得到objectvalues之间所有值的差值。最后,我们使用isEmpty 检查结果差异是否为空。

        function includesDeep(object, values) {
          return _(obj)
          .flatMap(function cb(v) { return _.isObject(v)? _.map(v, cb): v; })
          .thru(_.partial(_.difference, values))
          .isEmpty();
        }
        
        var result = includesDeep(obj, ['Stephen', 'Operations']);
        

        var obj = {
          id: 1,
          name: 'Stephen',
          age: 18,
          department: {
            id: 1,
            text: 'Operations'
          }
        };
        
        function includesDeep(object, values) {
          return _(obj)
          .flatMap(function cb(v) { return _.isObject(v)? _.map(v, cb): v; })
          .thru(_.partial(_.difference, values))
          .isEmpty();
        }
        
        var result = includesDeep(obj, ['Stephen', 'Operations']);
        
        console.log(result);
        &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"&gt;&lt;/script&gt;

        【讨论】:

          【解决方案5】:

          测试表明您无法使用 lodash 包含深入检查多值和值,因此您必须自己编写一个函数。

          您的解决方案

          describe('includes', () => {
              var value = {
                  foo: 'bar',
                  fuzz: 'buzz',
                  value2: {
                      key: 'value'
                  }
              };
          
              function includes(collection, values) {
                  return [].concat(values).every((value) => {
                      return Object.keys(collection).some((key) => {
                          let it = collection[key];
                          return typeof it == 'object' ? includes(it, value) : _.includes(it, value);
                      })
                  });
              }
          
              it('check single value', () => {
                  expect(includes(value, 'bar')).toBe(true);
                  expect(includes(value, 'baz')).toBe(false);
              });
          
              it('check multi values', () => {
                  expect(includes(value, ['bar', 'buzz'])).toBe(true);
                  expect(includes(value, ['baz', 'buzz'])).toBe(false);
              });
          
              it('check value in depth', () => {
                  expect(includes(value, 'value')).toBe(true);
                  expect(includes(value, 'no-exists')).toBe(false);
              });
          });
          

          测试

          describe('includes', () => {
              var value = {
                  foo: 'bar',
                  fuzz: 'buzz',
                  value2: {
                      key: 'value'
                  }
              };
          
              it('check single value', () => {
                  expect(_.includes(value, 'bar')).toBe(true);
                  expect(_.includes(value, 'baz')).toBe(false);
              });
          
              it('check multi values', () => {
                  expect(_.includes(value, ['bar', 'buzz'])).toBe(false);
                  expect(_.includes(value, ['baz', 'buzz'])).toBe(false);
              });
          
              it('check value in depth', () => {
                  expect(_.includes(value, 'value')).toBe(false);
              });
          });
          

          function includes(collection, values) {
              return [].concat(values).every(function (value) {
                  return Object.keys(collection).some(function (key) {
                      var it = collection[key];
                      return (typeof it == 'object') ? includes(it, value) : _.includes(it, value);
                  });
              });
          }
          
          
          var obj = {
            id: 1,
            name: 'Stephen',
            age: 18,
            department: {
              id: 1,
              text: 'Operations'
            }
          };
          
          
          var tests=[
            "Operations",
            "Non-Existing Value",
            ['Stephen', 'Operations'],
            ['Stephen', 'Non-Existing Value'],
          ];
          
          
          tests.forEach(function(test){
            console.log("includes(obj,"+JSON.stringify(test)+") => "+ includes(obj,test));
          });
          &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"&gt;&lt;/script&gt;

          【讨论】:

          • 我知道。这就是为什么我问是否有任何实用函数可以让我们使用像 _.includes() 这样的东西,但也能够深入遍历值。
          • 基于第三个库为您的解决方案编写一个函数,很简单。为什么要依赖其他库?搜索库可能会花费您很多时间。
          • 我已经更新了我的答案,看到Your solution,代码支持你的想法。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-03
          • 2019-04-29
          • 1970-01-01
          • 2020-11-13
          相关资源
          最近更新 更多