0

Bit of a weird one. Am using the following code build an array from a json object to make it easier to reference later in the code. However it would appear that when the last item of each array is created, rather than adding a new item, the Key of the item appears as the length of the array.

perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
    var obj = perfsJson[i];
    if (obj != null) {
        if (obj.Extras != null) {
            for (var perf_no in obj.Extras) {
                if (extras[perf_no] == undefined) {
                    var arr = new Array();
                    for (var extra in obj.Extras[perf_no]) {
                        if (arr[extra] == undefined) {
                            arr[extra] = obj.Extras[perf_no][extra];
                        }
                    }
                    extras[perf_no] = arr;
                }
            }
            break;
        }
    }
}

The resulting array appears as below:

resulting array

Any ideas what's going on here?

Edit: Sample of Json below

{"Extras":{"32516":{"24186":"Example text"},"32515":{"24186":"Example text"},"32514":{"24186":"Example text"},"32512":{"24186":"Example text"},"32513":{"24186":"Example text"},"32511":{"24186":"Example text"},"32510":{"24186":"Example text"},"32509":{"24186":"Example text"},"32507":{"24186":"Example text"},"32503":{"24186":"Example text"},"32506":{"24186":"Example text"},"32505":{"24186":"Example text"},"32508":{"24186":"Example text"},"32502":{},"32497":{}}}

3
  • You should generally try to avoid missing keys in Javascript arrays. If you need to use a particular key, you need an object or a Map instead. Commented Feb 14, 2017 at 12:06
  • Looks like you're using for...in loops with arrays, and you get the length as well. Commented Feb 14, 2017 at 12:07
  • 2
    The code seems like JS version of twitter.com/dr4goonis/status/476617165463105536 Commented Feb 14, 2017 at 12:08

1 Answer 1

1

What's going on hear is that you are using for..in to iterate over an array, which is a no-no because it iterates properties that are not the array elements (such as the .length property). Instead, use Array#forEach:

perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
  var obj = perfsJson[i];
  if (obj != null) {
    if (obj.Extras != null) {
      obj.Extras.forEach(function (item, idx) {
        if (typeof extras[idx] === 'undefined') {
          var arr = new Array();
          item.forEach(function (item2, idx2) {
              if (typeof arr[idx2] === 'undefined') {
                  arr[idx2] = item2;
              }
          });
          extras[idx] = arr;
        }
      });
      break;
    }
  }
}

The innermost loop is pretty pointless and can be replaced with Array#slice:

perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
  var obj = perfsJson[i];
  if (obj != null) {
    if (obj.Extras != null) {
      obj.Extras.forEach(function (item, idx) {
        if (typeof extras[idx] === 'undefined') {
          extras[idx] = item.slice();
        }
      });
      break;
    }
  }
}

The next inner loop can be replaced with Array#map and two if statements can be combined:

perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
  var obj = perfsJson[i];
  if (obj != null&& obj.Extras != null) {
    extras = obj.Extras.map(function (item) {
        return item.slice();
    });
    break;
  }
}

In fact, most of this code can be simplified:

function findLastElement(arr) {
    for (var i = arr.length - 1; i >= 0; i -= 1) {
        if (arr[i] != null && arr[i].Extras != null) { return arr[i]; }
    }
}

perfsJson = $.parseJSON(result);
var lastElement = findLastElement(perfsJson);
var extras = lastElement
    ? lastElement.Extras.map(function (item) { return item.slice(); })
    : [];
Sign up to request clarification or add additional context in comments.

6 Comments

Wow thanks, that's a seriously in depth answer. However if I try to use .forEach or .map I get an error saying "lastElement.Extras.map is not a function" or "lastElement.Extras.forEach is not a function". Any ideas?
@HuwD Is lastElement.Extras actually an array? Could you show us what your JSON looks like (not all of it, but a representative sample)? And what execution environment (browser, etc.) are you using?
I believe it's currently being handled as an object, have added sample of JSON to edit
@HuwD Thank you for adding that. Yes it is an object and it contains objects. Is there a reason you're trying to convert them into sparse arrays? Sparse arrays (arrays that have arbitrary indices instead of 0, 1, 2, 3, ...) are pretty unpopular and kind of hard to work with. It might be better if you just left them as objects.
Just to make it easier to reference from a later piece of code that uses another collection. The keys used for the top level array match up with values used in the later collection so I can match them up.
|

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.