简体   繁体   English

返回 object 将输入与嵌套对象进行比较

[英]Return object comparing input with nested objects

I am having an object that looks like this:我有一个 object,看起来像这样:

const obj = {
   "cat1" : { 
                id: "1", 
                name: "Category1", 
                tiles: [{ tileName: "abc", searchable: true}, { tileName: "def", searchable: true}]
             },
   "cat2" : { 
                id: "2", 
                name: "Category2", 
                tiles: [{ tileName: "ab", searchable: true}, { tileName: "lmn", searchable: true}]
             },
   "cat3" : { 
                id: "3", 
                name: "Category3", 
                tiles: [{ tileName: "pqr", searchable: true}, { tileName: "", searchable: false}]
             }

}

Based on the search input, I need to check if the search item is included in each object basically inside two fields.基于搜索输入,我需要检查搜索项是否包含在每个 object 中,基本上在两个字段内。 One is name and the other is tileName inside tile array ( should be searched only if that object has searchable true ).一个是name ,另一个是tile数组中的tileName (仅当 object 具有searchable的 true 时才应搜索)。 It should be searched across name and tiles array应该在nametiles数组中搜索

When search is "ab", the output should be当搜索是“ab”时,output应该是

const obj = {
   "cat1" : { 
                id: "1", 
                name: "Category1", 
                tiles: [{ tileName: "abc", searchable: true}]
             },
   "cat2" : { 
                id: "2", 
                name: "Category2", 
                tiles: [{ tileName: "ab", searchable: true}]
             },
}

Code that I tried我试过的代码

function handleSearch(search)
{
  return Object.values(obj).map((item) => {
    if(item["name"].toLowerCase().includes(item.toLowerCase()))
      return item;
    })
   })
}

I would personally create a generic filterMap() helper that combines the functionalities of both filter() and map()我会亲自创建一个通用的filterMap()助手,它结合了filter()map()的功能

// Combines filter() and map(). If no value is returned from the callback
// function (undefined) then the value is removed from the result. If a
// non-undefined value is returned, then that value is used as the map
// value. Returns a new array with the filtered/mapped values.
//
//     filterMap([1,2,3,4,5], (n) => { if (n % 2) return n * n })
//     //=> [1,9,25]
//
function filterMap(iterable, fn) {
  const filterMapped = [];
  for (const item of iterable) {
    const mapped = fn(item);
    if (mapped === undefined) continue; // skip current iteration
    filterMapped.push(mapped);
  }
  return filterMapped;
}

With the above helper defined you can get the desired functionality with relative ease使用上面定义的帮助程序,您可以相对轻松地获得所需的功能

function search(searchString, object) {
  const searchIn = (whole, part) => whole.toLowerCase().includes(part.toLowerCase());

  return Object.fromEntries(
    filterMap(Object.entries(object), ([key, { tiles, ...category }]) => {
      // If the category name matches, return the whole category as is,
      // without filtering the tiles.
      if (searchIn(category.name, searchString)) {
        return [key, { ...category, tiles }];
      }

      // If the category name did not match, filter the tiles.
      const matchingTiles = tiles.filter((tile) => (
        tile.searchable && searchIn(tile.tileName, searchString)
      ));

      // If there are one or more matching tiles found, return the
      // category with only the matching tiles.
      if (matchingTiles.length) {
        return [key, { ...category, tiles: matchingTiles }];
      }

      // If neither the category name nor one of the tiles matched,
      // nothing (undefined) is returned, thus the entry is removed
      // from the result.
    })
  );
}

 function search(searchString, object) { const searchIn = (whole, part) => whole.toLowerCase().includes(part.toLowerCase()); return Object.fromEntries( filterMap(Object.entries(object), ([key, { tiles, ...category }]) => { // If the category name matches, return the whole category as is, // without filtering the tiles. if (searchIn(category.name, searchString)) { return [key, {...category, tiles }]; } // If the category name did not match, filter the tiles. const matchingTiles = tiles.filter((tile) => ( tile.searchable && searchIn(tile.tileName, searchString) )); // If there are one or more matching tiles found, return the // category with only the matching tiles. if (matchingTiles.length) { return [key, {...category, tiles: matchingTiles }]; } // If neither the category name nor one of the tiles matched, // nothing (undefined) is returned, thus the entry is removed // from the result. }) ); } const obj = { "cat1": { id: "1", name: "Category1", tiles: [ { tileName: "abc", searchable: true }, { tileName: "def", searchable: true }, ], }, "cat2": { id: "2", name: "Category2", tiles: [ { tileName: "ab", searchable: true }, { tileName: "lmn", searchable: true }, ], }, "cat3": { id: "3", name: "Category3", tiles: [ { tileName: "pqr", searchable: true }, { tileName: "", searchable: false }, ], }, }; console.log('search "ab"', search("ab", obj)); console.log('search "3"', search("3", obj)); // helper // Combines filter() and map(). If no value is returned from the callback // function (undefined) then the value is removed from the result. If a // non-undefined value is returned, then that value is used as the map // value. Returns a new array with the filtered/mapped values. // // filterMap([1,2,3,4,5], (n) => { if (n % 2) return n * n }) // //=> [1,9,25] // function filterMap(iterable, fn) { const filterMapped = []; for (const item of iterable) { const mapped = fn(item); if (mapped === undefined) continue; // skip current iteration filterMapped.push(mapped); } return filterMapped; }

In the above code we use Object.entries() to convert the object to an array.在上面的代码中,我们使用Object.entries()将 object 转换为数组。 The array is then transformed using our newly defined filterMap() method.然后使用我们新定义的filterMap()方法转换数组。 Finally the resulting array is transformed back into an object using Object.fromEntries() .最后,使用Object.fromEntries()将生成的数组转换回 object。

The code makes use of destructuring , the spread syntax in object literals , and the property definition shorthand .该代码使用解构object 文字中的扩展语法属性定义速记


For those using TypeScript, filterMap() should be defined like:对于那些使用 TypeScript 的用户, filterMap()应该定义如下:

function filterMap<A, B>(iterable: Iterable<A>, fn: (item: A) => undefined | B): B[] {
  const filterMapped: B[] = [];
  for (const item of iterable) {
    const mapped = fn(item);
    if (mapped === undefined) continue; // skip current iteration
    filterMapped.push(mapped);
  }
  return filterMapped;
}

The answer might still leave you with:答案可能仍然留给你:

Not all code paths return a value.并非所有代码路径都返回一个值。 (7030) (7030)

In which case you must either explicitly return from the callback function.在这种情况下,您必须显式地从回调 function 中返回。

  // ...

  // If neither the category name nor one of the tiles matched,
  // nothing (undefined) is returned, thus the entry is removed
  // from the result.
  return; // <- explicit return at the end
})

Or alternatively set "noImplicitReturns": false in your TypeScript settings, to allow implicit returns.或者在您的 TypeScript 设置中设置"noImplicitReturns": false ,以允许隐式返回。

const obj = {"cat1":{"id":"1","name":"Category1","tiles":[{"tileName":"abc","searchable":true},{"tileName":"def","searchable":true}]},"cat2":{"id":"2","name":"Category2","tiles":[{"tileName":"ab","searchable":true},{"tileName":"lmn","searchable":true}]},"cat3":{"id":"3","name":"Category3","tiles":[{"tileName":"pqr","searchable":true},{"tileName":"","searchable":false}]}}

function search(obj, text) {
  return Object.values(obj)
    .map((item) => ({
      ...item,
      tiles: item.tiles.filter(tile => tile.searchable && tileName.includes(text))
    }))
    .filter(({tiles}) => tiles.length)
}

console.log(search(obj, 'ab'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM