2

Given a JS object like:

var obj = {
    p1: "v1",
    p2: "v2",
    ...,
    pn: "vn"
}

What I would like to do is to obtain an iterator over all distinct pairs of properties (both names or values would work for me).

So I could have a function like:

function(va, vb) {
    // do something with every pair
}

called once with each entry of the set of pairs ("v1", "v2"), ("v1", "v3"), ... , ("v1", "vn"), ("v2", "v3"), ... , ("v2", "vn"), ... , ("vn-1", "vn"). (A total of n(n - 1)/2 times)

The trivial solution is to have a double for ... in loop and discard the repetitions inside, but that's not either fast or elegant.

If it was an array and not an object we could have a different kind of iteration, like:

var len = obj.length;
for (var i = 0; i < len - 1; i++) {
    for (var j = i + 1; j < len; j++) {
        // do something with obj[i], obj[j]
    }
}

But I don't know any way to iterate an object like that (or if it would even make sense!).

Then, is there any fast and elegant way of doing this in javascript (or jQuery)?

Edit:

I don't want to get an iterator of (key, value) as suggested in some answers. I want an iterator over pairs of properties in an object.

I would like, for example, to run a check that verifies that every value is, at most, 10 units away from any other value.

function checkIsClose(v1, v2) {
    return ((v1 - v2) < 10 && (v1 - v2) >= 0)) || ((v2 - v1) < 10 && (v2 - v1) >= 0);
}
NublicPablo
  • 959
  • 11
  • 21

3 Answers3

3

Try this, Demo

var obj = {
    p1: "v1",
    p2: "v2",
    pn: "vn"
}

$.each(obj, function(a, b){alert(a);alert(b)});

Update:

$.each(obj, function(a, b1){

  $.each(obj, function(a, b2){
    console.log(b1 +" ,"+ b2);
  })

});

Demo

OutPut:

("v1", "v2"), ("v1", "v3"), ... , ("v1", "vn"), ("v2", "v3"), ... , ("v2", "vn"), ... , ("vn-1", "vn"). (A total of n(n - 1)/2 times)

https://api.jquery.com/jQuery.each/

dhana
  • 6,487
  • 4
  • 40
  • 63
  • Note that JavaScript objects aren't guaranteed, or required by the spec, to return values, or keys, in the order they were written (though most do, so far as I'm aware). To maintain any order an array should be used. – David Thomas May 05 '14 at 09:49
  • 1
    Sorry, buy the answer doesn't address the actual problem. The update is the same case of double loop, n^2: http://jsfiddle.net/dVGY2/1/ – NublicPablo May 05 '14 at 10:24
  • @NublicPablo I think you expecting like this http://jsfiddle.net/dhana36/dVGY2/2/ – dhana May 05 '14 at 10:43
  • 1
    Yes, but you are only hiding some cases, the inner function is still called n^2 times. It's not what I expected when I asked for a fast and elegant solution. @XiozZe 's answer is better in terms of performance. – NublicPablo May 05 '14 at 10:56
2

I can't think of an other way to iterate through an object like that without for ... in. But you can delete one key every time, that would make it a total of n(n - 1)/2 times.

http://jsfiddle.net/XiozZe/YTVAL/

var obj = {
    p1: "v1",
    p2: "v2",
    p3: "v3",
    p4: "v4",
    p5: "v5",
    p6: "v6",
}

//duplicate obj
var obj2 = {}
for (var i in obj) {
    obj2[i] = obj[i];
}

for(var i in obj2){
    for(var j in obj2){
        // do something with obj[i], obj[j]
    }
    delete obj2[i];
}

//obj2 is now empty
XiozZe
  • 464
  • 2
  • 7
  • 1
    This is a good answer so far, but it doesn't seem complete yet. It's the only one that targets the actual problem. Though, modifying an object inside the loop that iterates through it doesn't seem very safe. I would make the first loop to use obj, instead obj2. http://jsfiddle.net/aN5ZS/ – NublicPablo May 05 '14 at 10:21
0

Go for jQuery.map() like so:

jQuery.map(obj, function(vb, va) {
    // do something with every pair
});

Test it in the fiddle

mayrs
  • 2,299
  • 2
  • 24
  • 35