Getting javascript to search an array within an array
I have the following javascript to loop through an array of records, and alert the number of matches found within the array, for each field:
mymusic=[{title:"a",artist:"b",artwork:"c",tracks:[{tracktitle:"d",trackmp3:"e"}]}];
tracksArray=[];
trackTitles=[];
var albumScore=0;
var artistScore=0;
var tracksScore=0;
stringToSearchFor="d";
for(i=0;i<mymusic.length;i++){
if((mymusic[i].title).match(stringToSearchFor))
albumScore+=1;
}
if(albumScore!=0)
alert(albu开发者_开发百科mScore+" match(es) found in Albums");
else
alert("No matches found in Albums");
for(d=0;d<mymusic.length;d++){
if((mymusic[d].artist).match(stringToSearchFor))
artistScore+=1;
}
if(artistScore!=0)
alert(artistScore+" match(es) found in Artists");
else
alert("No matches found in Artists");
for(f=0;f<mymusic.length;f++){
tracksArray[f]=mymusic[f].tracks;
for(g=0;g<tracksArray;g++){
trackTitles[g]=tracksArray[g].tracktitle;
}
for(h=0;h<trackTitles.length;h++){
if(trackTitles(h).match(stringToSearchFor))
{
tracksScore+=1;
}
}
}
if(tracksScore!=0)
alert(tracksScore+" match(es) found in Tracks");
else
alert("No matches found in Tracks");
which works fine for the "title" and "artist" records, but always alerts "No matches found" for the "tracks" record, even when there are matches. I guess the problem is with the nested for-loop through the trackTitles array, but I can't see what I can change to make it work. Any ideas? Thanks
if(trackTitles(h)
You're calling an Array. Should be square brackets.
You could do with breaking out the array handling stuff into reusable functions to improve readability and reduce the number of these stray variables.
Since there are answers with procedural approaches already, here's one based on functional-like array handling for extra fun(*):
function countItemsContaining(seq, prop, str) {
return seq.map(itemGetter(prop)).filter(function(s) {
return s.indexOf(str)!==-1;
}).length;
}
function itemGetter(prop) {
return function(o) {
return o[prop];
};
}
mymusic= [{title:"a",artist:"b",artwork:"c",tracks:[{tracktitle:"d",trackmp3:"e"}]}];
needle= 'd';
var titleScore= countItemsContaining(mymusic, 'title', needle);
var artistScore= countItemsContaining(mymusic, 'artist', needle);
// Calling concat is a JavaScript idiom to combine a load of lists into one
//
var mytracks= [].concat.apply([], mymusic.map(itemGetter('tracks')));
var tracksScore= countItemsContaining(mytracks, 'tracktitle', needle);
array.map
and array.filter
are standardised in ECMAScript Fifth Edition, but aren't available in IE yet, so for compatibility you can define them like this:
if (!('map' in Array.prototype)) {
Array.prototype.map= function(f, that) {
var a= new Array(this.length);
for (var i= 0; i<this.length; i++) if (i in this)
a[i]= f.call(that, this[i], i, this);
return a;
};
}
if (!('filter' in Array.prototype)) {
Array.prototype.filter= function(f, that) {
var a= [];
for (var i= 0; i<this.length; i++) if (i in this)
if (f.call(that, this[i], i, this))
a.push(this[i]);
return a;
};
}
(*: amount of actual fun contained in answer may be limited)
Take a look at the library called underscore.js. It's made for this kind of stuff. These tasks often come down to a line or two of easy-to-read code.
It uses native methods when available, fills in the missing bits (depending on the browser) and is chainable. It even makes the built-in array methods chainable.
Try this instead:
var tracksScore=0;
stringToSearchFor="d";
for(var f=0;f<mymusic.length;f++){
var tracksArray=mymusic[f].tracks;
for(var g=0;g<tracksArray.length;g++) {
var tracktitle=tracksArray[g].tracktitle;
if(tracktitle.match(stringToSearchFor))
{
tracksScore+=1;
}
}
}
if(tracksScore!=0)
alert(tracksScore+" match(es) found in Tracks");
else
alert("No matches found in Tracks");
You have a number of basic errors which ultimately stem from having too many variables. Here is your code refactored:-
mymusic=[{title:"a",artist:"b",artwork:"c",tracks:[{tracktitle:"d",trackmp3:"e"}]}];
var albumScore=0;
var artistScore=0;
var tracksScore=0;
stringToSearchFor="d";
for (var i=0; i < mymusic.length; i++)
{
if( mymusic[i].title.match(stringToSearchFor))
albumScore += 1;
if( mymusic[i].artist.match(stringToSearchFor))
artistScore += 1;
for (var j = 0; j < mymusic[i].tracks.length; j++)
{
if (mymusic[i].tracks[j].tracktitle.match(stringToSearchFor))
tracksScore += 1
}
}
if (albumScore != 0)
alert(albumScore + " match(es) found in Albums");
else
alert("No matches found in Albums");
if (artistScore != 0)
alert(artistScore + " match(es) found in Artists");
else
alert("No matches found in Artists");
if (tracksScore != 0)
alert(tracksScore+" match(es) found in Tracks");
else
alert("No matches found in Tracks");
What AnthonyWJones and bobince said (although I'll need to spend some time reading through bobince's answer).
An alternative solution: The moment I saw the data structure I thought "recursion!" and thought it'd be fun to see if I could come up with a solution that would work with any size data structure of any (unknown) depth level.
I do not code frequently, so the below may be riddled with bad practices, but it works :). Let me know your thoughts.
myMusic=[{title:"a",artist:"b",artwork:"c",year:"d",tracks:[{tracktitle:"d",trackmp3:"e"}]}];
function find_match(dataObj,stringToSearchFor,resultObj){
resultObj = (resultObj)?resultObj:{}; //init resultObj
for (dataKey in dataObj){ //loop through dataObj
if (typeof(dataObj[dataKey]) == "object"){ //if property is array/object, call find_match on property
resultObj = find_match(dataObj[dataKey],stringToSearchFor,resultObj);
}else if (dataObj[dataKey].match(stringToSearchFor)){ //else see if search term matches
resultObj[dataKey] = (resultObj[dataKey] )?resultObj[dataKey] +=1:1; //add result to resultObj, init key if not yet found, use dataObj key as resultObj key
}
}
return resultObj; //return resultObj up the chain
}
results = find_match(myMusic,"d");
alertString = "";
for (resultKey in results){ //loop through results and construct alert msg.
alertString += results[resultKey] + " match(es) found in " + resultKey + "\n";
}
alert(alertString );
精彩评论