2

I'm hoping to find an efficient answer as as in the second answer (Rajesh Dhiman) in Jquery Count number of occurances in array

Javascript of JQuery are both acceptable.

Consider:

var items = new Array();
items.push({x: 1, y: "what"});
items.push({x: 3, y: "ever"});
items.push({x: 4, y: "can"});
items.push({x: 4, y: "happen"});
items.push({x: 1, y: "will"});
items.push({x: 4, y: "happen"});

Seeking results like (sorted or not doesn't matter):

res = {1:2, 3:1, 4:3}

All other related answers on here that I can find only consider counting simplistic arrays or not JS/JQ.

Community
  • 1
  • 1
Steve
  • 905
  • 1
  • 8
  • 32
  • Just had this thought. What if I wanted result in an array of anonymous objects such as `result = ({x: 1, y: 2}, {x: 3, y: 1}, {x: 4, y: 3})` ? @Nenad Vracar @NinaScholz – Steve Oct 11 '16 at 15:09
  • for now I'm just reprossessing `result` as `var res = new Array(); Object.getOwnPropertyNames(result).forEach(function(val, idx, array) { res.push({x: val, cnt: result[val]}); }); console.log(res);` – Steve Oct 11 '16 at 15:38

4 Answers4

4

You can use reduce() and return object as result.

var items = new Array();
items.push({x: 1, y: "what"});
items.push({x: 3, y: "ever"});
items.push({x: 4, y: "can"});
items.push({x: 4, y: "happen"});
items.push({x: 1, y: "will"});
items.push({x: 4, y: "happen"});

var result = items.reduce(function(r, o) {
  r[o.x] = (r[o.x] || 0) + 1;
  return r;
}, {})

console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • Just had this thought. What if I wanted result in an array of anonymous objects such as `result = ({x: 1, y: 2}, {x: 3, y: 1}, {x: 4, y: 3})` ? – Steve Oct 11 '16 at 15:30
  • for now I'm just reprossessing `result` as `var res = new Array(); Object.getOwnPropertyNames(result).forEach(function(val, idx, array) { res.push({x: val, cnt: result[val]}); }); console.log(res);` – Steve Oct 11 '16 at 15:40
2

No need for Array#reduce, an Array#forEach works well.

The result is an object. the reference does not change, so it is not necessary to use something which change the reference to a result.

If, for examle, a result is made of a countinuous addition, then the result would change, but here, with an object, it does not change. It is more some kind of laziness, to move an object through the reduce.

var items = [{ x: 1, y: "what" }, { x: 3, y: "ever" }, { x: 4, y: "can" }, { x: 4, y: "happen" }, { x: 1, y: "will" }, { x: 4, y: "happen" }],
    count = Object.create(null);

items.forEach(function(a) {
    count[a.x] = (count[a.x] || 0) + 1;
});

console.log(count);

As requested with an array of objects for the count. this proposal uses the this object hashing the included items in the result set.

var items = [{ x: 1, y: "what" }, { x: 3, y: "ever" }, { x: 4, y: "can" }, { x: 4, y: "happen" }, { x: 1, y: "will" }, { x: 4, y: "happen" }],
    result = [];

items.forEach(function(a) {
    if (!this[a.x]) {
        this[a.x] = { x: a.x, cnt: 0 };
        result.push(this[a.x]);
    }
    this[a.x].cnt++;
}, Object.create(null));

console.log(result);

With Array#reduce, a hash table as closure and an array.

var items = [{ x: 1, y: "what" }, { x: 3, y: "ever" }, { x: 4, y: "can" }, { x: 4, y: "happen" }, { x: 1, y: "will" }, { x: 4, y: "happen" }],
    result = items.reduce(function (hash) {
        return function(r, a) {
            if (!hash[a.x]) {
                hash[a.x] = { x: a.x, cnt: 0 };
                r.push(hash[a.x]);
            }
            hash[a.x].cnt++;
            return r;
        };
    }(Object.create(null)), []);

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • What would be a contrary remark for the use of reduce? – Steve Oct 11 '16 at 14:31
  • Same number of lines. Would just be a readability preference at this point. How would the performances compare? – Jecoms Oct 11 '16 at 14:31
  • I guess performance wise I should add that the array will only have at max maybe 70 objects. Typical around 35 ~40. In other words very small. – Steve Oct 11 '16 at 14:34
  • it's not a matter of speed, just some kind of programming style. – Nina Scholz Oct 11 '16 at 14:37
  • Just had this thought. What if I wanted result in an array of anonymous objects such as `result = ({x: 1, y: 2}, {x: 3, y: 1}, {x: 4, y: 3})` ? – Steve Oct 11 '16 at 15:30
  • @ninascholz for now I'm just reprossessing `result` as `var res = new Array(); Object.getOwnPropertyNames(result).forEach(function(val, idx, array) { res.push({x: val, cnt: result[val]}); }); console.log(res);` – Steve Oct 11 '16 at 15:41
  • Can't do that with reduce() can you :-) – Steve Oct 11 '16 at 19:32
  • reduce has not this object, bit if you really want, the you could use a closure and reduce (but i do not recommend it). – Nina Scholz Oct 11 '16 at 20:07
0

A quick and sorted solution :

var items = new Array();
items.push({x: 1, y: "what"});
items.push({x: 3, y: "ever"});
items.push({x: 4, y: "can"});
items.push({x: 4, y: "happen"});
items.push({x: 1, y: "will"});
items.push({x: 4, y: "happen"});
var res = items.map(x => ({x: x.x})).sort((a,b) => a.x - b.x).reduce((r,o) => {
    r[o.x] = (r[o.x] || 0) + 1;
    return r;
}, {});
console.log(res); //{ '1': 2, '3': 1, '4': 3 }
kevin ternet
  • 4,514
  • 2
  • 19
  • 27
0

Another approach would be to iterate over it and finding the occurrences. below is the code and the demo.

var items = new Array();
items.push({x: 1, y: "what"});
items.push({x: 3, y: "ever"});
items.push({x: 4, y: "can"});
items.push({x: 4, y: "happen"});
items.push({x: 1, y: "will"});
items.push({x: 4, y: "happen"});
var returnobj = {};

$.each(items, function(key, value) {
  if (returnobj.hasOwnProperty([value['x']])) {
    returnobj[value['x']] = returnobj[value['x']] + 1;
  } else {
    returnobj[value['x']] = 1;
  }
});
console.log(returnobj);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
WLatif
  • 1,330
  • 11
  • 19