Dexygen
Dexygen

Reputation: 12561

How to avoid using filter twice against the same set of elements

I'm trying to separate two types of inputs into their own jQuery wrapped sets as they need to be processed differently depending on whether the id contain '-add-new-' or not. I know I could do this using filter twice as follows:

var seriesTabInputs = $msSeriesTabs.find('input').filter(function() {
    return $(this).attr('id').indexOf('-add-new-') == -1;
});

var addNewTabInputs = $msSeriesTabs.find('input').filter(function() {
    return $(this).attr('id').indexOf('-add-new-') >= 0;
});

However filtering twice seems inefficient to me as I know it will require a second loop. Is there a way to avoid this?

Upvotes: 3

Views: 639

Answers (3)

Dexygen
Dexygen

Reputation: 12561

Avoiding filtering twice may not be so crucial unless you are dealing with an enormous amount of elements. Furthermore there is something to be said for the consistency of the code when you filter twice.

That being said there is a way to avoid filtering twice and it may even be instructional; below is some code that can be used to achieve this.

First, we create an empty wrapped set that can be added to, this is achieved by var seriesTabInputs = $(false); Please see this write-up for more information.

Then inside of the filter, we conditionally add to seriesTabInputs but note the way in which we do it: we continually re-assign with seriesTabInputs = seriesTabInputs.add($(this)); If instead you merely call seriesTabInputs.add($(this)) without assigning to seriesTabInput you will wind up with an empty array in the end. Please see the jQuery docs for .add() which gives a similar incorrect example and states that such usage "will not save the added elements, because the .add() method creates a new set".

var seriesTabInputs = $(false);

var addNewTabInputs = $msSeriesTabs.find('input').filter(function() {
    if ($(this).attr('id').indexOf('-add-new') >= 0) {
        return true;
    }
    else {
        seriesTabInputs = seriesTabInputs.add($(this));
    }
});

Upvotes: 0

thecodeparadox
thecodeparadox

Reputation: 87073

Try like below:

var addNewTabInputs = $msSeriesTabs.find('input[id*="-add-new-"]');
var seriesTabInputs = $msSeriesTabs.find('input[id]:not([id*="-add-new-"])');

OR

var addNewTabInputs = $msSeriesTabs.find('input[id*="-add-new-"]');
var seriesTabInputs = $msSeriesTabs.find('input[id]').not(addNewTabInputs);

Upvotes: 3

dsh
dsh

Reputation: 12213

Just to offer an alternative to using specific selectors, you could iterate through the jQuery set and build the two collections as you go. I don't know that this would be any faster due to the different operations applied to the collections.

var $inputs = $msSeriesTabs.find('input');
var seriesTabInputs = [];
var addNewTabInputs = [];
for (var i = 0; i < $inputs.length ; i += 1)
    {
    var input = $($inputs[i]);
    if ( $(input).attr('id').indexOf('-add-new-') >= 0 )
        { addNewTabInputs.push(input); }
    else
        { seriesTabInputs.push(input); }
    }

seriesTabInputs = $(seriesTabInputs);
addNewTabInputs = $(addNewTabInputs);

Upvotes: 1

Related Questions