jQuery / javascript find values within a list
I have a peculiar issue I'm dealing with. I'll start off vague and if anyone needs more detail I can give background on the project.
I have a selected ID (selected from a checkbox): 161
And I have many rows of IDs like so:
["161", "165", "573", "190", "150", "283"] // this one would be it
["160", "311", "793", "309", "301"]
["161", "165", "395", "306"] // this one would be it
["160", "311", "668", "191", "216", 开发者_C百科"301"]
I need to identify out of the rows of IDs above, which ones have the ID that has been selected. This isn't so difficult, I can loop through each row of IDs (looping through the actual array) and do thisIDList[i] == selectedID
.
Problem I'm having is when more than one ID has been selected: ["161", "306"]
Now I need to loop through the rows and identify which rows has both of the selected IDs.
["161", "165", "573", "190", "150", "283"] // wouldn't be it
["160", "311", "793", "309", "301"]
["161", "165", "395", "306"] // this one would be it
["160", "311", "668", "191", "216", "301"]
And so on. There can be anywhere from 1 to 5 or 6 IDs selected: ["161", "306", "216", "668"]
Can someone point me in the right direction? I think this is basically like comparing two lists where each item in List A needs to found in List B.
edit
I should add that the row can contain other IDs not found in the selected list. So if the selected IDs was ["161", "306"]
, then ["161", "165", "395", "306"]
would be a match still, even though it contains 165 and 395.
edit
Going to update and give a bit more info. I have a list of radio buttons:
<input type="checkbox" name="filter" value="301" />
<input type="checkbox" name="filter" value="161" />
<input type="checkbox" name="filter" value="573" />
<input type="checkbox" name="filter" value="190" />
I have an unordered list, each list has a data attribute (I'm using the metadata plugin):
<ul>
<li data="{attrID: '160,197,161,194,195,190,162' }">Lorem Ipsum</li>
</ul>
When a radio button is clicked:
// set the selected IDs
selectedIds = [];
$("input[name=filter]:checked").each(function(){
selectedIds.push(this.value);
});
// loop through each list
$('ul li').each(function () {
// get and set the metadata for the attrID key
meta = $(this).metadata();
idList = meta.attrID;
// find out if the selected IDs are found in this idList
var isMatch = matches(selectedIds,idList);
console.log(isMatch);
// my plan was to do this
if(isMatch){
// do something with this list item
}
});
This uses the inArray
function from jQuery. It returns an array containing the indices of the sets that contain all elements of the target set. If your sets are relatively small, as in your example, it should be fast enough.
function matches( target, sets )
{
var matches= [];
for (var i = 0, setsLen = sets.length; i < setsLen; ++i ) {
if (isSubset(target,sets[i])) {
matches.push(i);
}
}
return matches;
}
function isSubset( target, set )
{
for (var j = 0, targetLen = target.length; j < targetLen; ++j) {
if ($.inArray(target[j], set) < 0) {
return false;
}
}
return true;
}
A little test script based on your data:
$(function(){
var sets = [
["161", "165", "573", "190", "150", "283"],
["160", "311", "793", "309", "301"],
["161", "165", "395", "306"],
["160", "311", "668", "191", "216", "301"]
];
alert( matches( [ "161" ], sets ) );
alert( matches( [ "161","306" ], sets ) );
});
EDIT: I updated my example based on your additions. I think you'd only need to use the isSubset function. I'll leave the rest of the answer for context.
The fastest and most re-usable way of doing this is to create an isSubset function. You don't even depend on jQuery!
function isSubset(largeSet, smallSet){
for(var i=0; i<smallSet.length; i++){
if(largeSet.indexOf(smallSet[i]) == -1){
//not found.
return false;
}
}
return true;
}
Now iterate over all your ID list arrays and pass in your selected ID array:
isSubset(idList, selectedIds);
If the above returns true, you have identified a valid list !
=============
Edit: thanks to Eric, for pointing out a vulnerability with indexOf().
The following code should resolve that problem on all browsers:
if (!Array.indexOf) {
Array.prototype.indexOf = function (obj, start) {
for (var i = (start || 0); i < this.length; i++) {
if (this[i] == obj) {
return i;
}
}
return -1;
}
}
If you started by sorting each array, you'd only have to traverse each list once.
How about incrementing a variable when one of X id's have been found, and matching it against total selected Id's when it reaches the end. If 4 of 4 have been found, there is a match
精彩评论