-1

This is one of those questions I'm ashamed to even ask, but I'm working with an external JSON source and I'm forced to do something ugly. So here goes...

I have 'dirty' Javascript object, with property names containing a number at their end:

{ "Friend1" : "Bob",
  "Friend6" : "Fred",
  "Friend632" : "Gonzo",
  "FriendFinder1" : "Dolly",
  "FriendFinder4294" : "Jan"
}

I'm trying to figure out a way to clean-up/"zero-index" these property names so the object would look like:

{ "Friend0" : "Bob",
  "Friend1" : "Fred",
  "Friend2" : "Gonzo",
  "FriendFinder0" : "Dolly",
  "FriendFinder1" : "Jan"
}

I'm referencing this indexOf/Regex code: Is there a version of JavaScript's String.indexOf() that allows for regular expressions?

Any strategies you could recommend for doing this? I'll post where I'm at in a bit. Many thanks!

Community
  • 1
  • 1
Hairgami_Master
  • 5,429
  • 10
  • 45
  • 66
  • 3
    why don't you use arrays? `{"Friends":["Bob","Fred","Gonzo"], "FriendFinders":["Dolly","Jan"]}` ? – olsn Mar 28 '13 at 21:13

2 Answers2

1

Take the "base" of a key and append items with a common base to an array using the original index. (This produces a sparse array.) Then stretch it out again by enumerating each item with a common base into a new key with 'base'+enumeratedindex.

The trick here is to use a method like forEach to enumerate the array--this will only visit assigned items in a sparse array, allowing you to determine the sort order just by using the original index-part of the key.

If you don't have access to forEach, you can accomplish a similar task by including the key in the array items. Instead of an intermediate array like this:

{Friend: [undefined, "Bob", undefined, undefined, undefined, undefined, "Fred"]}

You have one like this:

{Friend: [[6, 'Fred'],[1, 'Bob']]}

Then you sort the array and visit each item in a foreach loop, extracting the second item.

Here is code:

function rekey(obj) {
    var rekey = /^(.*?)(\d+)$/;
    var nestedobj = {}, newobj = {};
    var key, basekeyrv, newkey, oldidx, newidx;
    function basekey(key) {
        return rekey.exec(key).splice(1);
    }
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            basekeyrv = basekey(key);
            newkey = basekeyrv[0];
            oldidx = parseInt(basekeyrv[1], 10);
            if (!nestedobj[newkey]) {
                nestedobj[newkey] = [];
            }
            nestedobj[newkey][oldidx] = obj[key];
        }
    }
    for (key in nestedobj) {
        if (nestedobj.hasOwnProperty(key)) {
            newidx = 0;
            nestedobj[key].forEach(function(item){
                newobj[key+newidx++] = item;
            });
        }
    }
    return newobj;
}


rekey({
  "Friend1" : "Bob",
  "Friend6" : "Fred",
  "Friend632" : "Gonzo",
  "FriendFinder1" : "Dolly",
  "FriendFinder4294" : "Jan"
});

produces

{Friend0: "Bob",
 Friend1: "Fred",
 Friend2: "Gonzo",
 FriendFinder0: "Dolly",
 FriendFinder1: "Jan"}

Alternatively, without using forEach:

function rekey(obj) {
    var rekey = /^(.*?)(\d+)$/;
    var nestedobj = {}, newobj = {};
    var key, basekeyrv, newkey, oldidx, newidx;
    function basekey(key) {
        return rekey.exec(key).splice(1);
    }
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            basekeyrv = basekey(key);
            newkey = basekeyrv[0];
            oldidx = parseInt(basekeyrv[1], 10);
            if (!nestedobj[newkey]) {
                nestedobj[newkey] = [];
            }
            nestedobj[newkey].push([oldidx, obj[key]]);
        }
    }
    for (key in nestedobj) {
        if (nestedobj.hasOwnProperty(key)) {
            nestedobj[key].sort();
            for (newidx = 0; newidx < nestedobj[key].length; newidx++) {
                newobj[key+newidx] = nestedobj[key][newidx][1];
            }
        }
    }
    return newobj;
}
Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • Holy crap man- you've gone beyond any possible amount of help I ever thought I would get on this. Thank you so much! This will take me a bit to digest, but I can't thank you enough for this. Cheers! – Hairgami_Master Mar 29 '13 at 14:25
  • Does this example disregard keys such as "Group" that don't have any number after them? I see your rekey regex targeting anycharactersequence+anynumbersequence but I can't quite grasp how it's being used. – Hairgami_Master Mar 29 '13 at 14:37
  • This code will start spewing errors about null values if any key in your object doesn't match the regex. It's used in the `basekey` function, which must return `['name', 'sortint']` for a given key. – Francis Avila Mar 29 '13 at 16:42
  • Many thanks- I added a check for valid regex sequence in the if(obj(has key) switch statement and it works perfectly. Again- thank you so much for doing this- I can't believe you did this for me. – Hairgami_Master Mar 29 '13 at 18:40
0

Could you try doing the following:

{
 friend: new Array(),
 friendFinder: new Array()
}

then you can:

friend.push() - Add to array

var index = friend.indexOf("Bob") - find in array

friend.splice(index, 1) - remove from the array at index the 1 is for the number to remove.

dj22
  • 245
  • 6
  • 18