如何使用过滤器在数组中搜索对象的多个键值?

Posted

技术标签:

【中文标题】如何使用过滤器在数组中搜索对象的多个键值?【英文标题】:How to use filter to search in multiple key values of objects in an array? 【发布时间】:2018-02-09 23:45:00 【问题描述】:

我有一个葡萄酒数组,其中包含带有每种葡萄酒数据的对象:

var wines = [
   _id: '59a740b8aa06e549918b1fda',
    wineryName: 'Some Winery',
    wineName: 'Pinot Noir',
    wineColor: 'Red',
    imageLink: '/img/FortBerensPN.png' ,
   _id: '59a7410aaa06e549918b1fdb',
    wineryName: 'Some Winery',
    wineName: 'Pinot Gris',
    wineColor: 'White',
    imageLink: '/img/FortBerensPG.png' ,
   _id: '59a74125aa06e549918b1fdc',
    wineryName: 'Some Winery',
    wineName: 'Rose',
    wineColor: 'Rose',
    imageLink: '/img/FortBerensRose.png' ,
   _id: '59a74159aa06e549918b1fdd',
    wineryName: 'Some other Winery',
    wineName: 'Rose',
    wineColor: 'Rose',
    imageLink: '/img/FortBerensRose.png' ,
   _id: '59a7417aaa06e549918b1fde',
    wineryName: 'Some other Winery',
    wineName: 'Pinot Gris',
    wineColor: 'White',
    imageLink: '/img/FortBerensPG.png' ,
   _id: '59a8721f4fd43b676a1f5f0d',
    wineryName: 'Some other Winery',
    wineName: 'Pinot Gris',
    wineColor: 'White',
    imageLink: '/img/FortBerensPG.png' ,
   _id: '59a872244fd43b676a1f5f0e',
    wineryName: 'Winery 3',
    wineName: 'Pinot Noir',
    wineColor: 'Red',
    imageLink: '/img/FortBerensPN.png'  ]

我可以弄清楚如何搜索(不区分大小写)葡萄酒对象,同时指定要搜索的对象的哪个键,如下所示:

var search = 'Noir'

filteredWines = function () 
  return wines.filter(function(wine)
    return (wine.wineName.toLowerCase().indexOf(search.toLowerCase())>=0;
  );
;

返回:

[  _id: '59a740b8aa06e549918b1fda',
    wineryName: 'Some Winery',
    wineName: 'Pinot Noir',
    wineColor: 'Red',
    imageLink: '/img/FortBerensPN.png' ,
   _id: '59a872244fd43b676a1f5f0e',
    wineryName: 'Winery 3',
    wineName: 'Pinot Noir',
    wineColor: 'Red',
    imageLink: '/img/FortBerensPN.png'  ]

但是,如果var search = 'Winery 3'var search = 'red' 显然不会返回任何结果,因为它正在查看数组中每个对象的wineName 的值。

那么有没有办法使用过滤器(或其他方法?)来搜索所有键值,甚至更好的是,多个指定的键值并返回匹配对象的数组?

类似:

filteredWines = function () 
  return wines.filter(function(wine)
    return ((wine.wineName.toLowerCase() && wine.wineName.toLowerCase() 
          && wine.wineName.toLowerCase()).indexOf(search.toLowerCase())>=0;
  );
;

还是我完全找错树了?

PS。我正在使用 Vue.js 2,所以如果在 vue 中有更好的方法,那么我会全力以赴!

【问题讨论】:

是否应该为每个属性搜索一个值?或者您是否为每个属性指定了不同的搜索值? 也许我误解了你的问题,但我认为简单地使用 OR 运算符就可以了?您可以通过创建函数 (wine.wineName.toLowerCase().indexOf(search.toLowerCase())>=0 来清理这部分。或者,您可以使用正则表达式。 顺便说一句,从人们最终发布的任何过滤方法中进行选择,但 computed property 将是在 Vue 中使用它的理想方式。 @Bert 我将其填充到计算属性中并返回结果 :) 感谢您向其他人说明这一点! 【参考方案1】:

你可以有一个更通用的函数来扫描所有字符串的属性。使用Object.values() 循环所有属性值,并在匹配后立即使用some 退出:

filteredWines = function (search) 
    var lowSearch = search.toLowerCase();
    return wines.filter(wine =>
        Object.values(wine).some(val => 
            String(val).toLowerCase().includes(lowSearch) 
        )
    );

如果您希望传递特定的键进行搜索:

filteredWines = function (search, keys) 
    var lowSearch = search.toLowerCase();
    return wines.filter(wine =>
        keys.some(key => 
            String(wine[key]).toLowerCase().includes(lowSearch) 
        )
    );

调用为

filteredWines('Winery 3', ['wineryName', 'wineName']);

【讨论】:

这太棒了,谢谢!再次感谢@Bert 为我精心制作了它 :) 节省了很多时间。谢谢。【参考方案2】:

使用“trincot”中的解决方案并将其更改为我的 angular5 应用程序:

filter(search, list): Observable<IFilteredList> 
  return list.filter(item => 
    return Object.values(item).some(val =>
      String(val).includes(search)
    );
  )

【讨论】:

【参考方案3】:

也可以这样:

    this.wines = this.wines.filter((item) => 
                return (item.wineryName.toString().toLowerCase().indexOf(val.toLowerCase()) > -1 ||
                item.wineName.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
                item.wineColor.toLowerCase().indexOf(val.toLowerCase()) > -1);
            )

【讨论】:

【参考方案4】:

我还建议尝试更通用的方法:

function getMatchingWhine(keys, searchTerm, wines) 

  function extractTextFromKeys(keys, object) 
    let text = '';
    keys.forEach(key => 
        text += ' ' + object[key];
    );
    return text.toLowerCase();
  

  return wines.filter(wine => 
    const relevantText = extractTextFromKeys(keys, wine);
    return relevantText.includes(searchTerm.toLowerCase());
  );

【讨论】:

【参考方案5】:

过滤器有效。糟糕,我更仔细地阅读了这个问题。过滤器仍然有效,但您也必须过滤值。

let wines = [
    
        _id: '59a740b8aa06e549918b1fda',
        wineryName: 'Some Winery',
        wineName: 'Pinot Noir',
        wineColor: 'Red',
        imageLink: '/img/FortBerensPN.png'
    ,
    
        _id: '59a7410aaa06e549918b1fdb',
        wineryName: 'Some Winery',
        wineName: 'Pinot Gris',
        wineColor: 'White',
        imageLink: '/img/FortBerensPG.png'
    ,
    
        _id: '59a74125aa06e549918b1fdc',
        wineryName: 'Some Winery',
        wineName: 'Rose',
        wineColor: 'Rose',
        imageLink: '/img/FortBerensRose.png'
    ,
    
        _id: '59a74159aa06e549918b1fdd',
        wineryName: 'Some other Winery',
        wineName: 'Rose',
        wineColor: 'Rose',
        imageLink: '/img/FortBerensRose.png'
    ,
    
        _id: '59a7417aaa06e549918b1fde',
        wineryName: 'Some other Winery',
        wineName: 'Pinot Gris',
        wineColor: 'White',
        imageLink: '/img/FortBerensPG.png'
    ,
    
        _id: '59a8721f4fd43b676a1f5f0d',
        wineryName: 'Some other Winery',
        wineName: 'Pinot Gris',
        wineColor: 'White',
        imageLink: '/img/FortBerensPG.png'
    ,
    
        _id: '59a872244fd43b676a1f5f0e',
        wineryName: 'Winery 3',
        wineName: 'Pinot Noir',
        wineColor: 'Red',
        imageLink: '/img/FortBerensPN.png'
    
];

let search = (val) => wines.filter(w => Object.values(w).filter(v => v.toLowerCase().indexOf(val.toLowerCase()) !== -1).length > 0);

console.log(search('some'));

【讨论】:

以上是关于如何使用过滤器在数组中搜索对象的多个键值?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 php/laravel 在现有数组对象中插入键值对?

使用 Big Query,我如何在一条记录中查询多个对象?

如何根据同一对象内给定的键值过滤对象

Vue JS按多个数组对象项过滤

如何在具有多个字符串的数组列表中搜索对象并返回对象?

Vue:过滤对象数组以进行搜索