0

I've been trying for days now to come up with a solution to my problem and I just can't, imagine I have the following JSON array (we shall call this jsonData:

[
  { "id": 118748, "price":"", "stocklevel": 100,   "instock": false, "pname": "Apple TV" },
  { "id": 118805291, "price":"", "stocklevel": 432,   "instock": true, "pname": "Hitachi TV"},
  { "id": 118801891, "price":"", "stocklevel": 0,   "instock": false, "pname": "Sony TV" },
  { "id": 118748, "price":"", "stocklevel": 2345,   "instock": true, "pname": "Apple TV"},
...

Now I may have over 100 items in my JSON array, I want to remove items which have a duplicate id, but sum the stock levels and retain the order in the array so a row should take the place of the latest occurrence of that id. In the above JSON the first instance of the object with "id": 118748 is removed but it's stock level value passed / added the next instance of an object with the same id, so the JSON Array would look like so:

[
  { "id": 118805291, "price":"", "stocklevel": 432,   "instock": true, "pname": "Hitachi TV"},
  { "id": 118801891, "price":"", "stocklevel": 0,   "instock": false, "pname": "Sony TV" },
  { "id": 118748, "price":"", "stocklevel": 2445,   "instock": true, "pname": "Apple TV"},
...

I produced the following code to remove the duplicates, but I can't sum the stock level totals, here is my code:

function idsAreEqual(obj1, obj2) {
    return obj1.id === obj2.id;
}

function arrayContains(arr, val, equals) {
    var i = arr.length;
    while (i--) {
        if (equals(arr[i], val)) {
            return true;
        }
    }
    return false;
}

function removeDups(arr, equals) {
    var originalArr = arr.slice(0);
    var i, k, len, val;
    arr.length = 0;

    for (i = originalArr.length - 1, len = originalArr.length, k  = originalArr.length - 1 ; i > 0; --i) {
        val = originalArr[i];

        if (!arrayContains(arr, val, equals)) {
            arr.push(val);
        }
    }
}


removeDups(jsonData, idsAreEqual);
jsonData.reverse();

Can someone please help me solve this problem? Please note that I cannot use Underscore, jQuery or any other library.

Big thanks in advance

1 Answer 1

4

You can do something like the following, which is a little simpler than your implementation I think. I also use forEach and reduce, which are ES5 but should work on modern browsers. You can grab a polyfil for either if you're working with older, non-ES5 compliant browsers:

var data = [
  { "id": 118748, "price":"", "stocklevel": 0,   "instock": false, "pname": "Apple TV" },
  { "id": 118805291, "price":"", "stocklevel": 432,   "instock": true, "pname": "Hitachi TV"},
  { "id": 118801891, "price":"", "stocklevel": 0,   "instock": false, "pname": "Sony TV" },
  { "id": 118748, "price":"", "stocklevel": 2345,   "instock": true, "pname": "Apple TV"}
];

function dedup_and_sum(arr, prop) {
    var seen = {},
        order = [];
    arr.forEach(function(o) {
        var id = o[prop];
        if (id in seen) {
            // keep running sum of stocklevel
            var stocklevel = seen[id].stocklevel + o.stocklevel
            // keep this newest record's values
            seen[id] = o;  
            // upid[118805291], stocklevel=432, instock=truedate stocklevel to our running total
            seen[id].stocklevel = stocklevel;
            // keep track of ordering, having seen again, push to end
            order.push(order.splice(order.indexOf(id), 1));
        }
        else {
            seen[id] = o;
            order.push(id);
        }
    });

    return order.map(function(k) { return seen[k]; });
}

// Get unique records, keeping last record of dups
// and summing stocklevel as we go
var unique = dedup_and_sum(data, 'id');
unique.forEach(function(o) {
    console.log("id[%d], stocklevel=%d, instock=%s", o.id, o.stocklevel, o.instock);
});
// output =>
// id[118805291], stocklevel=432, instock=true
// id[118801891], stocklevel=0, instock=false 
// id[118748], stocklevel=2445, instock=true

EDIT Updated to match requirements we discussed in comments.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for the great answer however I think I haven't explained myself very well... you see (please note updated jsonData) I wish to have the sum of the stock levels summed in the Json Data, so with the example above we remove the 1st item with the id of 118748 and add the stock level to the second (or final occurrence of the same id), so in the case above the first occurrence of id: 118748 is removed and it's stock level summed to the second occurrence, which would be 2445
Ok, so as you're removing the dups, you want to have the stocklevel be a running sum of all stocklevels seen for that particular id, right?
I have updated the question - I am really sorry for confusing you and explaining things so badly
Ok, that should do it. I moved the summing into the dedup function, renaming it to dedup_and_sum, so it will keep a running total of the stocklevel on the last seen record with that id.
That's great, however the positioning is wrong, I'd want id[118748] to be the last item in out outputted array, not the first, the order in the array so a row should take the place of the latest occurrence of that id. But what you have done has been a great help and has really educated me!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.