1

I am storing my array as a mixture of array an array and an object. For example assume this one:

let arrObj = [];
arrObj["x"] = 12;
arrObj.push(12);
arrObj["y"] = 15;
arrObj.push(15);

// result: arrObj = [12, 15, x: 12, y: 15]

so that, I can access the value 12 even using arrObj[0] and arrObj["x"]. And this way, I can do a repeat for on it.

But when I stringify it, the keys x and y get lost:

JSON.stringify(arrObj)
// result: "[12,15]"

How should I maintain those keys and their values?

Pranav C Balan
  • 106,305
  • 21
  • 136
  • 157
ConductedClever
  • 3,537
  • 1
  • 21
  • 54
  • 1
    This is not a valid JSON string: `"[ 12, 15, 'x': 12, 'y': 15 ]"`. Even if you output it, you won't be able to parse it as JSON. So it's not clear how this could work without some sort of transformation. – Mark Mar 30 '19 at 06:39
  • That's enough for me to make this structure valid for myself. I mean, at the other end I myself am catching the value, so that I can manipulate that end too. – ConductedClever Mar 30 '19 at 06:42
  • `[...arrObj.values()] // [12, 15] ` is the actual result. Dont confuse with x and y. They are just properties of `arrObj` array – User863 Mar 30 '19 at 06:46
  • @AswinKumar I want `x` and `y` for direct access in future. – ConductedClever Mar 30 '19 at 07:00
  • 1
    @ConductedClever Then Pranav C Balan's updated answer using object is abt for your case – User863 Mar 30 '19 at 07:03
  • 1
    Of course @AswinKumar. Thanks. – ConductedClever Mar 30 '19 at 07:03

3 Answers3

4

While stringifying convert it to an object using spread syntax and later parse and use Array#reduce method to generate the array.

The array keeps the property since Array is also an object in Javascript.

let arrObj = [];
arrObj["x"] = 12;
arrObj.push(12);
arrObj["y"] = 15;
arrObj.push(15);

let json = JSON.stringify({ ...arrObj });

console.log(json);

let parsed = Object.entries(JSON.parse(json)).reduce((arr, [key, value]) => (arr[key] = value, arr), []);

console.log(parsed);

FYI : But it always better to use an Object or Map for key-value pair data, not better that's the right way in my opinion.


UPDATE 1: Or you can use a main object which keeps all additional property and within it create a property which keeps the array as well.

let arrObj = {
  arr: []
};
arrObj["x"] = 12;
arrObj.arr.push(12);
arrObj["y"] = 15;
arrObj.arr.push(15);

let json = JSON.stringify(arrObj);

console.log(json);

let parsed = JSON.parse(json);

console.log(parsed);

UPDATE 2: The second approach cause issue if you are trying to set property named arr(in my case) so keep object values in separate property.

let arrObj = {
  arr: [],
  obj: {}
};
arrObj.obj["x"] = 12;
arrObj.arr.push(12);
arrObj.obj["y"] = 15;
arrObj.arr.push(15);

let json = JSON.stringify(arrObj);

console.log(json);

let parsed = JSON.parse(json);

console.log(parsed);
Pranav C Balan
  • 106,305
  • 21
  • 136
  • 157
0

Arrays should contain numeric-indexed values only. If you want keys in addition to values, use an object:

const obj = {};
obj.x = 12;
obj[0] = 12;
obj.y = 15;
obj[1] = 15;

console.log(JSON.stringify(obj));

for (let i = 0; i in obj; i++) {
  console.log(obj[i]);
}

You could also consider using an object that contains both an array and your custom key-value pairs, eg:

const arr = [];
const obj = { arr };
obj.x = 12;
obj.y = 15;
arr.push(12);
arr.push(15);

console.log(JSON.stringify(obj));
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • I want it to be an array to let foreach on it. This is not the answer of mine. – ConductedClever Mar 30 '19 at 06:30
  • If you want to preserve the arbitrary keys over stringification, use an object instead, and then transform it into an array when you need to use `forEach`. – CertainPerformance Mar 30 '19 at 06:31
  • And the transformation will force additional costs every time I call it. I think it is better to have it as array from the beginning. Although unless it be impossible. – ConductedClever Mar 30 '19 at 06:33
  • 1
    Stringified arrays *cannot* have arbitrary key-value pairs. If you need arbitrary key-value pairs to be saved over serialization, you have to use an object, not an array. – CertainPerformance Mar 30 '19 at 06:34
  • now the answer got better. And what about manipulating `JSON.stringify` itself to let arbitrary key-value pairs? – ConductedClever Mar 30 '19 at 06:39
  • 1
    If you do that, the result will not be valid JSON, and won't be parseable by anything but a custom parser you build, which would be difficult and a bad idea. – CertainPerformance Mar 30 '19 at 06:40
  • But the idea you call it bad is my desired way and I am looking for it. – ConductedClever Mar 30 '19 at 06:43
  • 1
    And if it's a custom parser, then by definition, you're not dealing with JSON, since JSON parses don't work. Also, wanting to foreach the array is a bad justification for breaking standards. – VLAZ Mar 30 '19 at 06:44
  • @ConductedClever I belueve yours is an XY problem - do you want to have a custom serialisation format *or* simply have a foreach-able object? – VLAZ Mar 30 '19 at 06:45
  • I'm not going to recommend/show the custom parsing technique that results in invalid JSON - like @VLAZ said, it's a bad idea, simply using an object instead is far easier. – CertainPerformance Mar 30 '19 at 06:47
0

Here is a fancy 1 liner solution:

let arrObj = [];
    arrObj["x"] = 12;
    arrObj.push(12);
    arrObj["y"] = 15;
    arrObj.push(15);

var string = JSON.stringify(Object.keys(arrObj).reduce((acc, cur) => ((acc[cur] = arrObj[cur]), acc), {}));

console.log(string);

P.S: I thought it's worthy to mention that you might encounter an unexpected behaviour because in JS, there is no guarantee that object properties are ordered (as you wanted to). Does JavaScript Guarantee Object Property Order?

Tyro Hunter
  • 683
  • 1
  • 8
  • 20