开发者

Better way to see if an array contains an object?

I have an array of items (terms), which will be put as <option> tags in a <select>. If any of these items are in another array (termsAlreadyTaking), they should be removed first. Here is how I have done it:

    // If the user has a term like "Fall 2010" already selected, we don't need that in the list of terms to add.
    for (var i = 0; i < terms.length; i++)
    {
        for (var iAlreadyTaking开发者_如何学运维 = 0; iAlreadyTaking < termsAlreadyTaking.length; iAlreadyTaking++)
        {
            if (terms[i]['pk'] == termsAlreadyTaking[iAlreadyTaking]['pk'])
            {
                terms.splice(i, 1); // remove terms[i] without leaving a hole in the array
                continue;
            }
        }
    }    

Is there a better way to do this? It feels a bit clumsy.

I'm using jQuery, if it makes a difference.

UPDATE Based on @Matthew Flaschen's answer:

// If the user has a term like "Fall 2010" already selected, we don't need that in the list of terms to add.
var options_for_selector = $.grep(all_possible_choices, function(elem)
                           {
                                var already_chosen = false;
                                $.each(response_chosen_items, function(index, chosen_elem)
                                {
                                    if (chosen_elem['pk'] == elem['pk'])
                                    {
                                        already_chosen = true;
                                        return;
                                    }
                                });
                                return ! already_chosen;
                           });

The reason it gets a bit more verbose in the middle is that $.inArray() is returning false, because the duplicates I'm looking for don't strictly equal one another in the == sense. However, all their values are the same. Can I make this more concise?


var terms = $.grep(terms, function(el)
            {
              return $.inArray(el, termsAlreadyTaking) == -1;
            });

This still has m * n performance (m and n are the lengths of the arrays), but it shouldn't be a big deal as long as they're relatively small. To get m + n, you could use a hashtable

Note that ECMAScript provides the similar Array.filter and Array.indexOf. However, they're not implemented in all browsers yet, so you would have to use the MDC implementations as a fallback. Since you're using jQuery, grep and inArray (which uses native indexOf when available) are easier.

EDIT:

You could do:

var response_chosen_pk = $.map(response_chosen_items, function(elem)
{
  return elem.pk;
});
var options_for_selector = $.grep(all_possible_choices, function(elem)
{
  return $.inArray(elem.pk, response_chosen_pk) == -1;
});


http://github.com/danstocker/jorder

Create a jOrder table on termsAlreadyTaking, and index it with pk.

var table = jOrder(termsAlreadyTaking)
    .index('pk', ['pk']);

Then you can search a lot faster:

...
if ([] == table.where([{ pk: terms[i].pk }]))
{
    ...
}
...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜