6

Please see this example: JsFiddle

Question: I have the following JSON Array

y= [ {"LngTrend":15,"DblValue":10,"DtmStamp":1358226000000},     
{"LngTrend":16,"DblValue":92,"DtmStamp":1358226000000},    
{"LngTrend":17,"DblValue":45,"DtmStamp":1358226000000},
{"LngTrend":18,"DblValue":87,"DtmStamp":1358226000000},


{"LngTrend":15,"DblValue":10,"DtmStamp":1358226060000},
{"LngTrend":16,"DblValue":87,"DtmStamp":1358226060000},
{"LngTrend":17,"DblValue":45,"DtmStamp":1358226060000},
{"LngTrend":18,"DblValue":92,"DtmStamp":1358226060000} ]

I was trying to group these object by DtmStamp end up having something like this :

 x =  [[1358226000000,10,92,45,87],[1358226060000,10,87,45,92], .......]

In other words:

x[0][0] = y[0].DtmStamp ;
x[0][1] = y[0].LngTrend ;
x[0][2] = y[1].LngTrend ;
x[0][3] = y[2].LngTrend ; 
x[0][4] = y[3].LngTrend ;

Unfortunately, it ends with something I don't want.

Here is what I have tried so far:

   var dataTrendArray = [];
           $.each(x, function (index, value) {
                var trendArray = [];
                if (index % 4 == 0) {
                    trendArray.push(x[index].DtmStamp);
                    for (var i = 0; i < 4; i++) {
                        index = eval(index + i);
                        trendArray.push(x[index].DblValue);
                    }
                }

               console.log(trendArray) ;
                dataTrendArray.push(trendArray);
            });

Can someone help me get on the right path?

Mina Gabriel
  • 23,150
  • 26
  • 96
  • 124

5 Answers5

17

You can leverage JavaScript objects as a key/value data structure similar to a map. The property name will serve as the key, while the property value will serve as the value. This will allow you to group.

var y = [
     {"LngTrend":15,"DblValue":10,"DtmStamp":1358226000000},     
     {"LngTrend":16,"DblValue":92,"DtmStamp":1358226000000},    
     {"LngTrend":17,"DblValue":45,"DtmStamp":1358226000000},
     {"LngTrend":18,"DblValue":87,"DtmStamp":1358226000000},
     {"LngTrend":15,"DblValue":10,"DtmStamp":1358226060000},
     {"LngTrend":16,"DblValue":87,"DtmStamp":1358226060000},
     {"LngTrend":17,"DblValue":45,"DtmStamp":1358226060000},
     {"LngTrend":18,"DblValue":92,"DtmStamp":1358226060000},
];

var x = {};

for (var i = 0; i < y.length; ++i) {
    var obj = y[i];

    //If a property for this DtmStamp does not exist yet, create
    if (x[obj.DtmStamp] === undefined)
        x[obj.DtmStamp] = [obj.DtmStamp]; //Assign a new array with the first element of DtmStamp.

    //x will always be the array corresponding to the current DtmStamp. Push a value the current value to it.
    x[obj.DtmStamp].push(obj.DblValue);
}

console.log(x); //x is now an object grouped by DtmStamp. You can easily turn it back into an array here.
crush
  • 16,713
  • 9
  • 59
  • 100
8

You should use a hash. A hash will allow you to easily index all of the DblValue values by DtmStamp. Here is a full working example:

jsFiddle

var y = [ {"LngTrend":15,"DblValue":10,"DtmStamp":1358226000000},     
{"LngTrend":16,"DblValue":92,"DtmStamp":1358226000000},    
{"LngTrend":17,"DblValue":45,"DtmStamp":1358226000000},
{"LngTrend":18,"DblValue":87,"DtmStamp":1358226000000},
{"LngTrend":15,"DblValue":10,"DtmStamp":1358226060000},
{"LngTrend":16,"DblValue":87,"DtmStamp":1358226060000},
{"LngTrend":17,"DblValue":45,"DtmStamp":1358226060000},
{"LngTrend":18,"DblValue":92,"DtmStamp":1358226060000} ];

var x = {};

var i = 0;
while(i++ < y.length) {
    var key = y[i].DtmStamp.toString();
    if (typeof(x[key]) == "undefined") x[key] = [];
    x[key].push(y[i].DblValue);
}

alert(JSON.stringify(x));

The key is to use a hash on the values you want to group by.

Result:

{
    "1358226060000": [
        92,
        45,
        87,
        10
    ],
    "1358226000000": [
        87,
        45,
        92,
        10
    ]
}

If you want to prevent duplicates, you can do so by adding if/then logic in conjunction with indexOf().

Elliot B.
  • 17,060
  • 10
  • 80
  • 101
  • 1
    While it is conceptually right to use an object, that linked article contains a few bad practises. Also, your code is a bit weird sometimes (backward iteration, explicit string conversion...) – Bergi Jan 29 '13 at 22:23
  • 1
    `while(i--){}` is a common thing to do. Nicholas Zakas promotes its use as the most efficient loop in JavaScript. Regarding the string conversion, I prefer explicit conversions--easier for others to follow imho. – Elliot B. Jan 29 '13 at 22:28
  • Not sure why anyone would care about those few saved microseconds, but the greater disadvantage is that it reverses the order and so does not match the OPs expected output. – Bergi Jan 29 '13 at 22:34
  • It's faster to type and faster to execute. Often times the order of the data doesn't matter. If it does, then the OP can go back to use `$.each` or a normal `i++` loop. – Elliot B. Jan 29 '13 at 22:46
  • looks good but ..why does the values are not in the proper order the first object should be [10,92,45,87] not [92,45,87,10] Thanks – Mina Gabriel Jan 30 '13 at 13:31
  • @MinaGabriel See the comments above. Change `var i = y.length` to `var i = 0` and `while(i--){}` to `while(i++ < y.length){}` and it'll retain the order you want. Answer updated. – Elliot B. Jan 30 '13 at 16:26
  • @ElliotB. The only issue I see: how do I iterate back the object assuming you don't know keys in advance? – Volatil3 Feb 05 '17 at 19:39
0

Your code pushes empty trendArrays even if they are not filled (index % 4 != 0). Instead, use this:

var dataTrendArray = [];
for (var i = 0; i < x.length; i += 4) {
    var trendArray = [ x[i].DtmStamp ];
    for (var j = i, l = Math.max(i + 4, x.length); j < l; j++) {
        trendArray.push(x[j].DblValue);
    }
    // console.log(trendArray) ;
     dataTrendArray.push(trendArray);
}

However, it might fit better if you just grouped the trendArrays into an object, using the DtmStamp as keys:

var dataTrend = {};
for (var i=0; i<x.length; i++) {
    var key = x[i].DtmStamp;
    if (key in dataTrend)
        dataTrend[key].push(x[i].DblValue);
    else
        dataTrend[key] = [ x[i].DblValue ];
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

You can build a sparse array, indexed by DtmStamp.

var x = [];
$.each(y, function(i, obj) {
    var s = obj.DtmStamp;
    if(!x[s]) x[s] = [];
    x[s].push(obj.DblValue);
});

//x is now a sparse array, indexed by DtmStamp

This has the advantage over an object, that the array elements are in DtmStamp order.

//To loop through x
for(i in x) {
    ...
}
Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • With `for in`, the order is not guaranteed even for arrays. – Bergi Jan 29 '13 at 22:38
  • @Bergi, you may well be correct but I ran some (admittedly limited) tests which demonstrated that `for(i in x)` looped through in order. Do you know the conditions under which the order will fail? – Beetroot-Beetroot Jan 29 '13 at 22:48
  • No, I haven't seen any browser in the wild that does not order numeric keys (because there's too much bad code expecting it). Still I cannot recommend it. – Bergi Jan 29 '13 at 23:19
  • 1
    My understanding is that a bigger issue with `for(prop in Array)` is that irrelevant properties may be found. A general solution is provided [here](http://hexmen.com/blog/2006/12/iterating-over-sparse-arrays/), though in the example above, a much simpler test would suffice, eg `if($.isArray(x[i]){...})`. – Beetroot-Beetroot Jan 29 '13 at 23:30
  • Yes, I guess [that](http://stackoverflow.com/q/500504/1048572) is the real issue. – Bergi Jan 30 '13 at 00:10
  • Just for example, [here](http://stackoverflow.com/q/14606640/1048572) the OP is experiencing unsorted numeric properties from a JSON object – Bergi Jan 30 '13 at 14:46
  • @Bergi, interesting that browsers should behave differently with that data, but is that not a slightly different issue from this one? This OP doesn't have "numeric" keys; rather numeric values, which are transformed by my suggested code into array indexes. At no point do I introduce a "numerically" keyed js plain object. Or am I missing the point? – Beetroot-Beetroot Jan 30 '13 at 21:48
  • Yeah, it was not meant to be related to your answer. Just you asked above under which conditions a for-in-loop did not order numeric keys, and I found an example for such inconsistencies. – Bergi Jan 30 '13 at 22:01
0
 var y = [
   {"LngTrend":15,"DblValue":10,"DtmStamp":1358226000000},     
   {"LngTrend":16,"DblValue":92,"DtmStamp":1358226000000},    
   {"LngTrend":17,"DblValue":45,"DtmStamp":1358226000000},
   {"LngTrend":18,"DblValue":87,"DtmStamp":1358226000000},
   {"LngTrend":15,"DblValue":10,"DtmStamp":1358226060000},
   {"LngTrend":16,"DblValue":87,"DtmStamp":1358226060000},
   {"LngTrend":17,"DblValue":45,"DtmStamp":1358226060000},
   {"LngTrend":18,"DblValue":92,"DtmStamp":1358226060000},
 ];
var x = {};

for(var k in y){
  if(x[y[k]["DtmStamp"]] == undefined)
     x[y[k]["DtmStamp"]] = [];
     x[y[k]["DtmStamp"]].push(y[k]["DblValue"])
}
alert(JSON.stringify(x))
console.log(x);

See http://plnkr.co/edit/511sKSdzHGYuvpYqKCPD?p=preview

user3772857
  • 601
  • 1
  • 8
  • 8