通过搜索嵌套对象属性过滤对象数组
Posted
技术标签:
【中文标题】通过搜索嵌套对象属性过滤对象数组【英文标题】:Filtering array of objects by searching nested object properties 【发布时间】:2018-01-16 10:05:27 【问题描述】:我有一个对象数组,我想通过将嵌套属性与搜索词进行比较来过滤它们。
例如:
var array = [
category: 'Business'
users: [
name: 'Sally'
tags: [tag: 'accounting', tag: 'marketing',...]
,
name: 'Bob'
tags: [tag: 'sales', tag: 'accounting',...]
...
]
,
category: 'Heritage'
users: [
name: 'Linda'
tags: [tag: 'Italy', tag: 'Macedonia',...]
,
name: 'George'
tags: [tag: 'South Africa', tag: 'Chile',...]
,...
]
,...
[
本质上,我想通过搜索项过滤对象的基本数组,其中包括嵌套对象 2 个数组中标签属性字符串中的字符。
所以搜索“市场”会导致
[
category: 'Business'
users: [
name: 'Sally'
tags: [tag: 'accounting', tag: 'marketing',...]
,
name: 'Bob'
tags: [tag: 'sales', tag: 'accounting',...]
...
]
]
谢谢。
【问题讨论】:
【参考方案1】:您可以使用Array#filter
通过Array#some
查看嵌套数组。
如果在嵌套数组中找到标记,则迭代停止并将结果返回给过滤器回调。
var array = [ category: 'Business', users: [ name: 'Sally', tags: [ tag: 'accounting' , tag: 'marketing' ] , name: 'Bob', tags: [ tag: 'sales' , tag: 'accounting' ] ] , category: 'Heritage', users: [ name: 'Linda', tags: [ tag: 'Italy' , tag: 'Macedonia' ] , name: 'George', tags: [ tag: 'South Africa' , tag: 'Chile' ] ] ],
tag = 'marketing',
result = array.filter(a => a.users.some(u => u.tags.some(t => t.tag.includes(tag))));
console.log(result);
.as-console-wrapper max-height: 100% !important; top: 0;
【讨论】:
如果我想比较两个值?【参考方案2】:使用Array.prototype.some()
函数的解决方案:
var arr = [ category: 'Business', users: [ name: 'Sally', tags: [ tag: 'accounting' , tag: 'marketing' ] , name: 'Bob', tags: [ tag: 'sales' , tag: 'accounting' ] ] , category: 'Heritage', users: [ name: 'Linda', tags: [ tag: 'Italy' , tag: 'Macedonia' ] , name: 'George', tags: [ tag: 'South Africa' , tag: 'Chile' ] ] ],
search_key = 'market',
result = [];
arr.forEach(function(o)
if (o.users.some(function(v)
return v.tags.some(function(i) return i.tag.indexOf(search_key) !== -1; );
))
result.push(o);
);
console.log(result);
【讨论】:
这是一个很好的答案罗马,谢谢。我刚刚接受了 Nina 的,因为首先添加了她的并且更简洁一些。干得好。【参考方案3】:试试这个:
function search(term)
return
Array.filter(array,function(item)
return JSON.stringify(obj).indexOf(term)!=-1;
);
所以:
console.log(search('market'));
希望对你有帮助:)
【讨论】:
这也会搜索键,所以如果你搜索“tag”,你会发现每个对象都匹配。【参考方案4】:concatAll
和 concatMap
定义取自 http://reactivex.io/learnrx/
Array.prototype.concatAll = function()
var results = [];
this.forEach(function(subArray)
results.push.apply(results, subArray);
);
return results;
;
Array.prototype.concatMap = function(projectionFunctionThatReturnsArray)
return this.
map(function(item)
return projectionFunctionThatReturnsArray(item);
).
// apply the concatAll function to flatten the two-dimensional array
concatAll();
;
function filterByTags(keyword)
return array.filter(function (item)
var allTags = item.users.concatMap(function (user)
return user.tags.map(function (tag)
return tag.tag;
);
);
return allTags.some(function (tag)
return tag.indexOf(keyword) > -1;
);
);
console.log(filterByTags('market'));
当然,您可以内联 allTags
变量以获得更简洁。
应用于初始数组的filter
将返回其标签包含所提供关键字的用户的所有项目。策略是构建用户标签的扁平化版本并在其上应用some
。
【讨论】:
【参考方案5】:你可以像这样使用array.filter
:
function getFiltered(val)
return array.filter(category == val);
此函数将返回一个新的数组实例,仅使用您作为 val
参数传递的 category
键。
【讨论】:
【参考方案6】:注意:我对此采取了类似捷径的方法,主要是为了提供不同的视角来解决问题。
您可以创建 users
属性的 json 字符串并在其中搜索,而不是深入搜索主 array
下的属性和数组。因此,我创建了一个新属性 usersString
,该属性临时存储针对 users
属性的值的 JSON 字符串。
item.usersString = JSON.stringify(item.users);
现在,这不是一个完美的实现,但它几乎总是可以工作的。此外,如果您将此属性存储在浏览器中(而不将其存储回数据库),并在每次用户搜索时使用它来快速搜索,我认为它会比深度搜索整个数组更高效。
var array = [
category: 'Business',
users: [
name: 'Sally',
tags: [
tag: 'accounting'
,
tag: 'marketing'
]
,
name: 'Bob',
tags: [
tag: 'sales'
,
tag: 'accounting'
]
]
,
category: 'Heritage',
users: [
name: 'Linda',
tags: [
tag: 'Italy'
,
tag: 'Macedonia'
]
,
name: 'George',
tags: [
tag: 'South Africa'
,
tag: 'Chile'
]
]
];
var key = "market";
// Convert the users property into a string - so that it works as a quick search target.
array.forEach(function(item)
item.usersString = JSON.stringify(item.users);
);
var filteredItems = array.filter(function(item)
return item.usersString.toLowerCase().indexOf(key.toLowerCase()) >= 0;
);
// Delete the usersString property - if required.
filteredItems.forEach(function(item)
item.usersString = undefined;
// Or,
// delete item.usersString;
)
console.log(filteredItems);
【讨论】:
以上是关于通过搜索嵌套对象属性过滤对象数组的主要内容,如果未能解决你的问题,请参考以下文章
Javascript通过包含搜索词的标签子数组过滤或减少每个JSON对象