我需要帮助一些我正在努力的小事。我必须创建一个通用搜索输入,搜索音乐数字的json。用户必须能够在搜索栏中键入专辑/曲目或艺术家,然后他才能获得结果。像任何其他搜索栏一样。只有这一个基于按键而不是提交按钮进行搜索。
我遇到的部分是我收到了一个包含5000多个条目的大型JSON文件。我的搜索栏必须能够根据部分键入的"关键字"来识别条目。所以,例如,如果我想搜索麦当娜,我输入" mado"我应该已经在我的结果中获得了一些麦当娜(当然可以获得其他在他们的标题中有mado的条目或者某些东西!)。
很抱歉我缺乏良好的语法,但我会尽力解释这种情况尽可能好!
现在提出问题!我正在解决的问题是我如何遍历json文件来搜索这些关键字。这是我收到的json的一小部分:
{
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}}
通常我会创建一个类似这样的函数:
for(var i = 0; i < data.length; i++){
if(data[i].album == 'red hot'){
console.log(data[i].album)
}}
但在这种情况下,我想循环遍历json,查找包含搜索值的enties并将其保存到对象以供以后使用
是否可以一次完成所有操作?那么要一次检查艺术家/标题/专辑,还是创建一个小过滤器会更好?
如果我的解释不明确,请认识我,我尽力尽可能清楚!
答案 0 :(得分:1)
我不认为搜索5000个条目会导致性能问题。
查看此代码,当您致电search('text')
var data = JSON.parse('JSON DATA HERE') // dataset
var search_fields = ['track','artist','album'] //key fields to search for in dataset
function search(keyword){
if(keyword.length<1) // skip if input is empty
return
var results = []
for(var i in data){ // iterate through dataset
for(var u=0;u<search_fields.length;u++){ // iterate through each key in dataset
var rel = getRelevance(data[i][search_fields[u]],keyword) // check if there are matches
if(rel==0) // no matches...
continue // ...skip
results.push({relevance:rel,entry:data[i]}) // matches found, add to results and store relevance
}
}
results.sort(compareRelevance) // sort by relevance
for(i=0;i<results.length;i++){
results[i] = results[i].entry // remove relevance since it is no longer needed
}
return results
}
function getRelevance(value,keyword){
value = value.toLowerCase() // lowercase to make search not case sensitive
keyword = keyword.toLowerCase()
var index = value.indexOf(keyword) // index of the keyword
var word_index = value.indexOf(' '+keyword) // index of the keyword if it is not on the first index, but a word
if(index==0) // value starts with keyword (eg. for 'Dani California' -> searched 'Dan')
return 3 // highest relevance
else if(word_index!=-1) // value doesnt start with keyword, but has the same word somewhere else (eg. 'Dani California' -> searched 'Cali')
return 2 // medium relevance
else if(index!=-1) // value contains keyword somewhere (eg. 'Dani California' -> searched 'forn')
return 1 // low relevance
else
return 0 // no matches, no relevance
}
function compareRelevance(a, b) {
return b.relevance - a.relevance
}
答案 1 :(得分:0)
这是我经常用于过滤功能的模式。一些关键点是:
始终构建一个索引属性,该属性包含可过滤值的附加字符串。例如,如果可以过滤“track”,“artist”和“album”的值,则将它们的值连接到一个字符串中,并将该字符串作为其中一个属性添加到原始对象中。
这有助于使用indexOf
快速搜索,而不必在过滤时迭代每个对象。它显着提高了性能,因为不再需要这些迭代和额外的number of properties*number of objects
比较。在您的情况下,每次过滤操作都会节省大约10k的比较和15k次迭代。
如果过滤器操作不区分大小写,请在将值附加到构建索引时使用toLowerCase
。每次调用过滤器时,它还可以避免执行那么多toLowerCase
个操作。
始终创建一个对象数组,而不是具有对象属性的对象。我没有关于这是否会提高性能的具体统计信息,但它为您提供了一些可用于改进UX的数组方法,例如array.filter
或array.sort
。我在片段中没有这样做,但是在准备数据时你可以很容易地做到这一点。
var data = {
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}};
// One time activity!
// Build search indexes, for every object.
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var index = "";
var item = data[prop];
// Iterate over each object and build the index by appending the values of each property.
for(var attr in item) {
if(item.hasOwnProperty(attr)) {
// Note: Different values are separated by a hash as hash # is unlikely to come into the search query.
index = index + item[attr] + "#";
}
}
// Insert the index property into the object.
// Also notice the toLowerCase that allows for case insenstive searches later on.
item.index = index.toLowerCase();
}
}
console.log("Prepared data:" ,data);
// Filter process.
var key = "Sn";
var keyLowerCase = key.toLowerCase();
// Iterate over the objects and compare the index prpoerty to match with the search string.
var filteredData = [];
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var item = data[prop];
if(item.index.indexOf(keyLowerCase) >= 0 ){
filteredData.push(item);
}
}
}
console.log("Filtered data:", filteredData);