views:

312

answers:

3

Okay, I'm not sure how to describe what i want to do concisely. So, take the following pseudo-html:

<input type=checkbox id=chk1 myatr=1 />
<input type=checkbox id=chk2 myatr=1 />
<input type=checkbox id=chk3 myatr=2 />
<input type=checkbox id=chk4 myatr=1 />
<input type=checkbox id=chk5 myatr=2 />
<input type=checkbox id=chk6 myatr=3 />

What i want to do is select all the checkboxes where they are the first occurrence of their respective value for "myatr". So i want to take something like:

$('input [type=checkbox]')

and extend it somehow to only get the items with ids chk1, chk3 and chk6, as they are the first instances of their values of myatr (1, 2 and 3 respectively).

Something like:

$('input [type=checkbox]').FirstForEach('myatr')

Is this possible somehow?

+1  A: 

Not an elegant solution, but you can do something like this:

var attrs = new Array();

$("input [type=checkbox]").
  filter(
    function() {
      attr = this.attr("myatr");
      if ( array_contains(attrs, attr)) {
        return false;
      } else {
        array_insert(attrs, attr);
        return true;
      }
  ).
  ...

array_contains and array_insert should be implemented :)

Zed
You shouldn't use `new Array()` in JS, you should just use `[]`
RaYell
You can just use attrs.push(attr) instead of array_insert(attrs, attr)
dalbaeb
+1  A: 

I don't think you can get that just calling jQuery build-in selectors. However you can easily get this in a few lines of code.

var ids = [];
$('input[type=checkbox]').filter(function (index) {
    var attr = $(this).attr('myattr');
    if (ids.indexOf(attr) !== -1) {
        ids[ids.length] = attr;
        return true;
    }
    return false;
});

Untested but should work.

Note: IE doesn't have Array.indexOf method implemented but you can easily fix that with this code:

[].indexOf || (Array.prototype.indexOf = function(v){
    for (var i = 0; i < this.length; i++) {
        if (v === this[i]) {
            return i;
        }
    }
    return -1;
});
RaYell
An array is not really required. You can just use an object as a hashmap for faster results.
Chetan Sastry
+1  A: 

Zed's solution using objects (behaving like hashmaps) giving O(1) lookups as opposed to O(n) lookup of Array.

var attrs = {};
var prefix = "blah$$";
$("input [type=checkbox]").
  filter(
    function() {
      attr = this.attr("myatr");
      if (attrs[prefix + attr]) {
        return false;
      } else {
        attrs[prefix + attr] = true;
        return true;
      }
  )

A prefix is used to avoid collisions with built-in properties of object.

Chetan Sastry
It would be interesting to measure how long attribute list it takes to actually have that o(1) of hashing go below the o(n) of array access.
Zed
Performance wise, it must be a really long array (1000+) elements to take notice. But objects are just right for this purpose. Also, look at the extra code you have to write implementing array_contains.
Chetan Sastry