【问题标题】:Search in all json's elements with lodash.js使用 lodash.js 在所有 json 元素中搜索
【发布时间】:2017-02-20 13:55:02
【问题描述】:

朋友们,我有对象 json:

  var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

我正在编写一个函数,用于返回带有我作为参数(过滤器)传递的元素的新 json。我做一个简单的

   function searchBooks(companies,filter){
    var result;
      if (typeof filter=== "undefined" ||  filter.length==0) {
          result = companies;
      } else {
        result = _.filter(companies, function (c) {
         return _.includes(_.lowerCase(c.name),_.lowerCase(filter));
       });
     }
 }

使用我的函数,我只能按名称过滤,我的问题是:我如何按名称、管理员、国家、城市过滤,除了 id,例如,如果你在变量中传递 4 应该返回:

{ id: 3, name: "新公司", admin: "Admin 4" }

或者如果我搜索 iLl 应该返回:

{ id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }

谢谢

【问题讨论】:

  • 那不是JSON,它是一个对象数组。 JSON 是一种数据交换格式,其格式类似于 JS 的子集。字符串 '[{"id":1},{"id":2}]' 是 JSON 格式的数据,可以将 parsed 转换为 JS 数组:[{id: 1}, {id: 2}]。它可能看起来像语义,但它是一个重要的区别。

标签: javascript json lodash


【解决方案1】:

下面的搜索功能利用filter()text 搜索中获取匹配的对象。为了确定一个对象是否与搜索到的text 匹配,我们对集合中每个对象的所有值使用some()some() 方法使用includes() 测试小写形式的对象中的每个值与搜索到的text 的小写形式。

请注意,我使用了toLower(),而不是lowerCase(),因为后者将字符串转换为小写格式作为分隔的单词,而前者则完全转换整个字符串,而不管字符串的大小写格式——你可以根据您的要求选择以其他方式切换它。

更新:当测试来自搜索到的text 的对象值时,我添加了一个排除参数作为omit() 某些属性的一种方式。

function searchByText(collection, text, exclude) {
  text = _.toLower(text);
  return _.filter(collection, function(object) {
    return _(object).omit(exclude).some(function(string) {
      return _(string).toLower().includes(text);
    });
  });
}
console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));

var companies = [{
    id: 1,
    name: "Test Company",
    admin: "Test Admin"
  },
  {
    id: 2,
    name: "Another Company",
    admin: "Test Admin",
    country: 'Spain'
  },
  {
    id: 3,
    name: "New Company",
    admin: "Admin 4"
  },
  {
    id: 4,
    name: "Free Company",
    admin: "Jhon Miller",
    city: 'New York'
  }
];

function searchByText(collection, text, exclude) {
  text = _.toLower(text);
  return _.filter(collection, function(object) {
    return _(object).omit(exclude).some(function(string) {
      return _(string).toLower().includes(text);
    });
  });
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

这是使用partial()flow() 的上述解决方案的组合版本

function searchByText(collection, text, exclude) {
  return _.filter(collection, _.flow(
    _.partial(_.omit, _, exclude),
    _.partial(
      _.some, _,
      _.flow(_.toLower, _.partial(_.includes, _, _.toLower(text), 0))
    )
  ));
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));

var companies = [{
    id: 1,
    name: "Test Company",
    admin: "Test Admin"
  },
  {
    id: 2,
    name: "Another Company",
    admin: "Test Admin",
    country: 'Spain'
  },
  {
    id: 3,
    name: "New Company",
    admin: "Admin 4"
  },
  {
    id: 4,
    name: "Free Company",
    admin: "Jhon Miller",
    city: 'New York'
  }
];

function searchByText(collection, text, exclude) {
  return _.filter(collection, _.flow(
    _.partial(_.omit, _, exclude),
    _.partial(
      _.some, _,
      _.flow(_.toLower, _.partial(_.includes, _, _.toLower(text), 0))
    )
  ));
}

console.log(searchByText(companies, '4'));
console.log(searchByText(companies, 'iLl'));
console.log(searchByText(companies, '4', ['id']));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

【讨论】:

  • 谢谢@ryeballar。您的 2 个解决方案非常优雅,但我需要知道如何排除过滤器的 ID?因为如果我写 4 显示 2 寄存器并且应该只显示 1 : { id: 3, name: "New Company", admin: "Admin 4" },
  • 谢谢!您的解决方案 100% 有效。
【解决方案2】:

Object.keys() 是关键 ;)

试试这个:

var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

function searchBooks(filter){
    var result;
      if (typeof filter=== "undefined" ||  filter.length==0) {
          result = companies;
      } else {
        result = _.filter(companies, function (c) {

         // This part will transform every property value in a single string.
         var searchIn = Object.keys(c).reduce(function(res, val) { return (val !== 'id')?res+c[val]:res }, '');
         return _.includes(_.lowerCase(searchIn),_.lowerCase(filter));
       });
     }
     console.log(result)
 }
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<input type="text" onKeyUp="searchBooks(this.value)">

【讨论】:

  • 谢谢@SteevePitis,您的解决方案是有效的,但我需要知道如何排除过滤器的 ID,因为如果我写 4 显示 2 个寄存器并且应该只显示 1 个。
  • 如果你只想显示第一个结果,那么你只需要return result[0]
  • 我知道这一点,但我的问题是搜索时是否可以排除 id 。想象一下其他寄存器有 "4" ,应该返回 2 个寄存器没有 3 。谢谢
  • 我不太确定你想要什么。您想显示除 ID 为 X 的结果以外的所有结果(例如,2)?
  • 哦,我想我明白了,你想从搜索列表中删除键 'id' 吗?
【解决方案3】:

如何以相同的方式搜索每个属性,指定您的潜在搜索键,请参阅searchBooksSpecificProperties

或者,如果您总是想搜索所有字段,您可以使用_.keys() 获取每个项目的键,请参阅searchBooks

var companies= [
    { id: 1, name: "Test Company", admin: "Test Admin" },
    { id: 2, name: "Another Company", admin: "Test Admin", country: 'Spain' },
    { id: 3, name: "New Company", admin: "Admin 4" },
    { id: 4, name: "Free Company", admin: "Jhon Miller", city: 'New York' }
];

function searchBooks(companies, filter){
  var result;
    if (typeof filter=== "undefined" ||  filter.length==0) {
        result = companies;
    } else {
      result = _.filter(companies, function (c) {
        var cProperties = _.keys(c);
        _.pull(cProperties, 'id');
        return _.find(cProperties, function(property) {
          if (c[property]) {
            return _.includes(_.lowerCase(c[property]),_.lowerCase(filter));
          }          
        });         
     });
   }
   return result;
 }

 console.log('searchBooks:');
 console.log(searchBooks(companies, 'Admin 4'))
 console.log(searchBooks(companies, 'York'))
 
function searchBooksSpecificProperties(properties, companies, filter){
  var searchSpecificProperties = _.isArray(properties);
  var result;
    if (typeof filter=== "undefined" ||  filter.length==0) {
        result = companies;
    } else {
      result = _.filter(companies, function (c) {
        var cProperties = searchSpecificProperties ? properties : _.keys(c);
        return _.find(cProperties, function(property) {
          if (c[property]) {
            return _.includes(_.lowerCase(c[property]),_.lowerCase(filter));
          }          
        });         
     });
   }
   return result;
 }
 console.log('searchBooksSpecificProperties:');
 console.log(searchBooksSpecificProperties(['name', 'admin'], companies, 'Admin 4'))
 console.log(searchBooksSpecificProperties(['name', 'admin'], companies, 'York'))
&lt;script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 感谢@Apostolidis,但我如何才能使用仅接收 2 个参数的函数来做到这一点? ,没有属性
  • 我更改了答案,添加了 2 个不同的功能。你可以看到searchBooks()searchBooksSpecificProperties()
猜你喜欢
  • 1970-01-01
  • 2017-08-22
  • 2012-09-09
  • 2010-11-29
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 2022-08-10
  • 1970-01-01
相关资源
最近更新 更多