Stringify an JS Object in Asc order - javascript

I have an js object like
{
a: 1,
b: 2,
c: 3
}
I wanted to stringify the above object using JSON.stringify with the same order. That means, the stringify should return me the strings as below,
"{"a":"1", "b":"2", "c":"3"}"
But it is returning me like the below one if my js object has too many properties say more than 500,
"{"b":"2", "a":"1", "c":"3"}"
Is there any option to get my js object's json string as in sorted in asc.

If the order is important for you, don't use JSON.stringify because the order is not safe using it, you can create your JSON stringify using javascript, to deal with string values we have 2 different ways, first to do it using regexp an replace invalid characters or using JSON.stringify for our values, for instance if we have a string like 'abc\d"efg', we can simply get the proper result JSON.stringify('abc\d"efg'), because the whole idea of this function is to stringify in a right order:
function sort_stringify(obj){
var sortedKeys = Object.keys(obj).sort();
var arr = [];
for(var i=0;i<sortedKeys.length;i++){
var key = sortedKeys[i];
var value = obj[key];
key = JSON.stringify(key);
value = JSON.stringify(value);
arr.push(key + ':' + value);
}
return "{" + arr.join(",\n\r") + "}";
}
var jsonString = sort_stringify(yourObj);
If we wanted to do this not using JSON.stringify to parse the keys and values, the solution would be like:
function sort_stringify(obj){
var sortedKeys = Object.keys(obj).sort();
var arr = [];
for(var i=0;i<sortedKeys.length;i++){
var key = sortedKeys[i];
var value = obj[key];
key = key.replace(/"/g, '\\"');
if(typeof value != "object")
value = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
arr.push('"' + key + '":"' + value + '"');
}
return "{" + arr.join(",\n\r") + "}";
}

The JavaScript objects are unordered by definition (you may refer to ECMAScript Language Specification under section 8.6, click here for details ).
The language specification doesn't even guarantee that, if you iterate over the properties of an object twice in succession, they'll come out in the same order the second time.
If you still required sorting, convert the object into Array apply any sorting algorithm on it and then do JSON.stringify() on sorted array.
Lets have an example below as:
var data = {
one: {
rank: 5
},
two: {
rank: 2
},
three: {
rank: 8
}
};
var arr = [];
Push into array and apply sort on it as :
var mappedHash = Object.keys( data ).sort(function( a, b ) {
return data[ a ].rank - data[ b ].rank;
}).map(function( sortedKey ) {
return data[ sortedKey ];
});
And then apply JSON.stringy :
var expectedJSON = JSON.stringify(mappedHash);
The output will be:
"[{"rank":2},{"rank":5},{"rank":8}]"

Related

Return the key from a JavaScript array?

Using PHP I can return the key by looking up the value inside an array.
<?php
$array = array(
'fruit1' => 'apple',
'fruit2' => 'orange',
'fruit3' => 'grape',
'fruit4' => 'apple',
'fruit5' => 'apple');
while ($fruit_name = current($array)) {
if ($fruit_name == 'apple') {
echo key($array).'<br />';
}
next($array);
}
?>
But I'm learning javascript, I've searched and haven't found a solution, I'm still a beginner.
How can I return the key by fetching the value within a given array?
I've already tried using its functions: .indexOf() or .findIndex()
var array = [];
array['key'] = 'Value';
array['car'] = 'Ferrari';
array['car2'] = 'BMW';
console.log(key='Ferrari'??);
How to Return 'car' if Value = 'Ferrari' ?
another doubt in this case is it better to use Array or Class? Is it possible to return the class key?
var pessoas = {'car': 'Ferrari', 'car2':'BMW'};
Arrays don't have keys, only numeric indexes. When you pass a string to an Array, you are actually creating a new property for the Array object, not a new item in the Array data (for example, .length is a property of an Array, not an indexed value).
var array = [];
// The following 3 lines don't create indexed values in the array:
array['key'] = 'Value';
array['car'] = 'Ferrari';
array['car2'] = 'BMW';
// Which is proven here:
console.log(array.length); // 0
// What they do is create new properties on the Array instance:
console.log(array.car2); // "BMW"
If you need keys, use an object, which is structured as follows:
{key: keyValue, key: keyValue, key:keyValue ...}
where the key is always a string, so quotes around the key name are not necessary.
var pessoas = {car: 'Ferrari', car2:'BMW'};
console.log("The second car is: " + pessoas.car2);
console.log("The keys and key names are: ");
for (var prop in pessoas){
console.log(prop + " : " + pessoas[prop]);
}
You should use Objects instead of arrays in JavaScript to store PHP equivalent of arrays with keys. In JS if you make an array, add non numeric keys to it and then do .length it will give 0. So many built in functions do not work, like .filter .find and .map.
//your way
let pessoas = [];
pessoas ["car1"] = "Ferrari";
pessoas ["car2"] = "BMW";
//the safe way. Both ways work.
pessoas = {'car': 'Ferrari', 'car2':'BMW'};
function getObjKey(obj, value) {
return Object.keys(obj).find(key => obj[key] === value);
}
console.log(getObjKey(pessoas, 'BMW'));
Additionally, you can turn string-keyed arrays into object like this:
function getObjKey(obj, value) {
return Object.keys(obj).find(key=>obj[key] === value);
}
var arrayToObject = (array)=>Object.keys(array).reduce((acc,curr)=>(acc[curr] = array[curr],
acc), {});
let pessoas = [];
pessoas["car1"] = "Ferrari";
pessoas["car2"] = "BMW";
pessoas.push("corretArray");
pessoas = arrayToObject(pessoas);
console.log(getObjKey(pessoas, 'BMW'));

JS: Finding next key in json

I have the following json:
{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}
Currently I am trying to get its key-value with the below code:
var data = JSON.stringify(row);
var result = $.parseJSON(data);
$.each(result, function (k, v) {
//display the key and value pair
console.log(k, v);
});
The above code works fine and I can get my key-value from it.
Now what I am trying to get is the next key-value pairs within the $.each loop.
For example if in the loop the current key is "0" I want to get the next key "1" in the same call itself. If in the loop the current key is "1" I want to get the next key "$$hashKey" along with their values.
Is it possible to do so? I am open to code changes above if required.
You can use Object.keys to get the keys to an array, then run through it with a forEach to have access to the keys index. Important to note that objects are unordered, so your key order one time may differ from the next time:
var keys = Object.keys(obj);
keys.forEach(function(key, index) {
var nextIndex = index + 1;
if (nextIndex === keys.length) return; //out of bounds
var nextKey = keys[nextIndex];
});
Edit: As pointed out by the comments - if you want the keys in the same order each time, call .sort() on your keys array with your desired sort logic.
Understanding now that the goal is to retrieve keys in the order they appear in JSON, a couple of thoughts:
(1) if you control the source of the object ("row" in the OP code), don't represent it as an object. instead use an array of key-value pairs: [[0, "2"], [1, "2"], [$$hashKey, "object:35"], [undefined, "1"]].
otherwise, (2) roll your own JSON parser that returns an array of key-value pairs for an object. This post looks to be a sensible start. Or, you can vastly simplify the task if you are able to make certain assumptions about the values, for example, say you know that all values are strings...
// parse a string representing an object, returning an array of key-value pairs.
// assumes values are strings that do not contain commas or colons
function myProbablyNegligentlySimpleJSONParse(string) {
let trimmed = string.trim().slice(1, -1);
let components = trimmed.split(',');
return components.map(kvString => {
let kv = kvString.split(':');
return [ kv[0].trim(), kv[1].trim() ];
});
}
forEach passes the current index to the iterator function, so that int can be used to look ahead or behind in the iteration.
var data = '{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}';
let result = myProbablyNegligentlySimpleJSONParse(data);
result.forEach(function (pair, index) {
let [k, v] = pair; // now k and v are your key and value
console.log(`key is ${k} value is ${v}`)
if (index < result.length-1) {
let [nextK, nextV] = result[index+1];
console.log(`next key is ${nextK} next value is ${nextV}`);
}
});
You could turn your object into an iterable and which will return the next [key, value] pair each time you call next on the iterator:
function makeIterable(o) {
o[Symbol.iterator] = () => {
var keys = Object.keys(o);
var i = 0;
return {
next() {
var done = false;
var value = [keys[i + 1], o[keys[i + 1]]];
if (i >= (keys.length - 1)) {
done = true;
}
i++;
return {
value,
done
}
}
};
}
}
var jsonStr = '{ "0": "2", "1": "2", "$$hashKey": "object:35", "undefined": "1" }';
var obj = JSON.parse(jsonStr);
makeIterable(obj);
var itr = obj[Symbol.iterator]();
while (true) {
var item = itr.next();
if (item.done) {
break;
}
console.log(item.value);
}

Efficiently or more functionally create an object from an array

Is there a more functional way to create an object in JavaScript programatically without assigning each key individually?
For example, given this array (imagine it comes from an outside data source):
let arr = ['a=1', 'b=2', 'c=3'];
What is an easy way to convert this to an object like so?
let expectedResult = { a: '1', b: '2', c: '3'};
It's clunky to assign a new object and loop over the elements with a for or foreach. It would be nice if there were something akin to map that could yield such a final result.
Imagine you could do this:
arr
.map(item => new KeyValuePair(itemKey, itemValue)) // magically get itemKey/itemValue
.toObjectFromKeyValuePairs();
That'd be it right there. But of course there's no such function built in.
If you're looking for a more functional approach to the code, you could use a library such as Lodash which makes code more succinct.
You could use _.fromPairs to convert pairs of data in arrays to key-value pairs of an object.
const convert = arr => _(arr)
.map(s => _.split(s, '=', 2))
.fromPairs()
.value();
console.log(convert(['a=1', 'b=2', 'c=3']));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You could use reduce, split and slice:
var arr = ['a=1', 'b=2', 'c=3'];
var out = arr.reduce(
function (output, input) {
if (typeof input === 'string') {
var key = input.split('=',1)[0];
output[key] = input.slice( key.length + 1 );
}
return output;
},
{}
);
I use the second argument of split to make it stop after the first = found. Then using slice on the input (treating it as an array of characters) allows the value to contain the = separator as in the case of a=b=c.
By using slice, the value will always be a string, even if it is an empty one. If you want to have null values you could change the line to:
output[key || null] = input.slice( key.length + 1 ) || null;
The type check for string is present since split throws error on null and undefined.
If you wanted to parse the current page's query string for example, you could do it using the above technique just like this:
function getQueryStringParams() {
var reEncodedSpace = /\+/g;
return location.search.length > 1 // returns false if length is too short
&& location.search.slice( 1 ).split( '&' ).reduce(
( output, input ) => {
if ( input.length ) {
if ( output === false ) output = {};
input = input.replace( reEncodedSpace, ' ' ); //transport decode
let key = input.split( '=', 1 )[ 0 ]; // Get first section as string
let value = decodeURIComponent( input.slice( key.length + 1) ); // rest is value
key = decodeURIComponent( key ); // transport decode
// The standard supports multiple values per key.
// Using 'hasOwnProperty' to detect if key is pressent in output,
// and using it from Object.prototype instead of the output object
// to prevent a key of 'hasOwnProperty' to break the code.
if ( Object.prototype.hasOwnProperty.call( output, key ) ) {
if ( Array.isArray( output[ key ] ) ) {
// Third or more values: add value to array
output[ key ].push( value );
} else {
// Second value of key: convert to array.
output[ key ] = [ output[ key ], value ];
}
} else {
// First value of key: set value as string.
output[ key ] = value;
}
}
return output;
},
false
);
}
The function returns false if the search is empty.
If you're willing to spare having one additional line for declaration, this could work for you. Although using a library like lodash or underscore, as mentioned in other answers would certainly help:
var arr = ['a=1', 'b=2', 'c=3'];
var expectedResult = {};
arr.map(function(value) {
var kv = value.split("=");
expectedResult[kv[0]] = kv[1];
return value
})
Try The Below Code.
let arr = ['a=1', 'b=2', 'c=3'];
let b=arr.toString();
b='{"'+(b.split('=').join('":"').split(',').join('","'))+'"}';
b=$.parseJSON(b);
console.log(b);
You will get the required output.

How to read arrays in Json using JavaScript

I have a Json data as listed below:
var x = {
"array1":"['x1','x2']",
"array2":"['a1', 'a2']"
}
I need to print the individual elements of the array as below
x1
x2
a1
a2
When I do var y = JSON.parse(x), it gives me "Unexpected token o"
It seems to be coming from the JSON.parse line. If I do x = '["x1", "x2"]', there is no error but I need to have two arrays in the JSON. So how do I read them
Thanks for any answers
That is not JSON. JSON is a string and not an object hence its abbreviation of JavaScript Object Notation. What you have is colloquially referred to as a POJO or Plain Old JavaScript Object. They are different. The former is a data exchange format similar to YAML or XML while the latter is an actual object with properties and values.
Your POJO does have JSON values but since it is already an object you can't use JSON.parse to parse the entire object. That is where the "o" is coming from in the error message. JSON.parse will coerce the first argument to a string if it is not a string:
var foo = {};
JSON.parse(foo); // is essentially doing this foo.toString() which is "[object Object]"
JSON.parse('{}'); // This would parse to an empty object though since it is a string
So now when it attempts to parse "[object Object]" it sees what may be an array but then encounters a character that hasn't been quoted, the "o" in "object", and therefore throws an error.
For your example to be JSON you would need to write it as:
var json = '{"array1":["x1","x2"],"array2":["a1","a2"]}';
var x = JSON.parse(json);
document.write('<pre>' + JSON.stringify(x, null, 4) + '</pre>');
And so, now that we have a real JSON value we can answer your original question:
var json = '{"array1":["x1","x2"],"array2":["a1","a2"]}';
var x = JSON.parse(json);
var vals = Object.keys(x).sort().reduce(function (arr, key) {
arr = arr.concat(x[key]);
return arr;
}, []).join('\n');
document.write('<pre>' + vals + '</pre>');
I think your JSON should be like the following
{
"array1": ["x1", "x2"],
"array2": ["a1", "a2"]
}
Create your array in many different ways - two examples
var x = [{array1:['x1','x2']},{array2:['a1','a2']}]
x[1].array2 produces ["a1", "a2"]
x[1].array2[0] produces "a1"
var xx = {array1:['x1','x2'],array2:['a1','a2']}
xx.array2 produces ["a1", "a2"]
xx.array2[0] produces "a1"
third example
var xxx = {array1:{x1:'x1',x2:'x2'},array2:{a1:'a1',a2:'a2'}}
xxx.array1.x1 produces "x1"
What you have there, that 'x' variable var x = {"array1":[...]...} is already a javascript object, so you can simply pass through the object keys and display the values.
Given 'x' as the object you can have something like:
var key,
result = '';
for (key in x) {
if (x.hasOwnProperty(key)) {
result = result + x[key].join('\n') + '\n';
}
}
// There you have the result...
As John said earlier, for JSON.parse() you wold need a string as a parameter to be able to parse it into a javascript object.
so, you can use this script to do that (correct json too - http://jsonformatter.curiousconcept.com/ -, don't know why this downrate.....i guess a noob didnt realize :D):
var x = {
"array1": ["x1", "x2"],
"array2": ["a1", "a2"]
}
for (var key in x) {
if (x.hasOwnProperty(key)) {
document.getElementById("test").innerHTML += key + " -> " + x[key]+" <br>";
}
}
i've created a working fiddle here:
https://jsfiddle.net/rjzzqLmr/1/

Adding elements to object

I need to populate a json file, now I have something like this:
{"element":{"id":10,"quantity":1}}
And I need to add another "element". My first step is putting that json in a Object type using cart = JSON.parse, now I need to add the new element.
I supposed I must use cart.push to add another element, I tried this:
var element = {};
element.push({ id: id, quantity: quantity });
cart.push(element);
But I got error "Object has no method push" when I try to do element.push, and I think I'm doing something VERY wrong because I'm not telling the "element" anywhere.
How can I do that?
Edit: sorry to all I had a LOT of confusion in my head.
I thought I can get only object type when taking data from JSON.parse, but I get what I put in the JSON in the first place.
Putting array instead of object solved my problem, I used lots of suggestions got here too, thank you all!
Your element is not an array, however your cart needs to be an array in order to support many element objects. Code example:
var element = {}, cart = [];
element.id = id;
element.quantity = quantity;
cart.push(element);
If you want cart to be an array of objects in the form { element: { id: 10, quantity: 1} } then perform:
var element = {}, cart = [];
element.id = id;
element.quantity = quantity;
cart.push({element: element});
JSON.stringify() was mentioned as a concern in the comment:
>> JSON.stringify([{a: 1}, {a: 2}])
"[{"a":1},{"a":2}]"
The line of code below defines element as a plain object.
let element = {}
This type of JavaScript object with {} around it has no push() method. To add new items to an object like this, use this syntax:
element[yourKey] = yourValue
To put it all together, see the example below:
let element = {} // make an empty object
/* --- Add Things To The Object --- */
element['active'] = true // 'active' is the key, and 'true' is the value
console.log(element) // Expected result -> {type: true}
element['state'] = 'slow' // 'state' is the key and 'slow' is the value
console.log(element) // Expected result -> {type: true, state: 'slow'}
On the other hand, if you defined the object as an array (i.e. using [] instead of {}), then you can add new elements using the push() method.
To append to an object use Object.assign
var ElementList ={}
function addElement (ElementList, element) {
let newList = Object.assign(ElementList, element)
return newList
}
console.log(ElementList)
Output:
{"element":{"id":10,"quantity":1},"element":{"id":11,"quantity":2}}
If the cart has to be stored as an object and not array (Although I would recommend storing as an []) you can always change the structure to use the ID as the key:
var element = { quantity: quantity };
cart[id] = element;
This allows you to add multiple items to the cart like so:
cart["1"] = { quantity: 5};
cart["2"] = { quantity: 10};
// Cart is now:
// { "1": { quantity: 5 }, "2": { quantity: 10 } }
Adding new key/pair elements into the original object:
const obj = { a:1, b:2 }
const add = { c:3, d:4, e: ['x','y','z'] }
Object.entries(add).forEach(([key,value]) => { obj[key] = value })
obj new value:
{a: 1, b: 2, c: 3, d: 4, e: ['x', 'y', 'z'] }
I was reading something related to this try if it is useful.
1.Define a push function inside a object.
let obj={push:function push(element){ [].push.call(this,element)}};
Now you can push elements like an array
obj.push(1)
obj.push({a:1})
obj.push([1,2,3])
This will produce this object
obj={
0: 1
1: {a: 1}
2: (3) [1, 2, 3]
length: 3
}
Notice the elements are added with indexes and also see that there is a new length property added to the object.This will be useful to find the length of the object too.This works because of the generic nature of push() function
you should write var element = [];
in javascript {} is an empty object and [] is an empty array.
cart.push({"element":{ id: id, quantity: quantity }});
function addValueInObject(object, key, value) {
var res = {};
var textObject = JSON.stringify(object);
if (textObject === '{}') {
res = JSON.parse('{"' + key + '":"' + value + '"}');
} else {
res = JSON.parse('{' + textObject.substring(1, textObject.length - 1) + ',"' + key + '":"' + value + '"}');
}
return res;
}
this code is worked.
Try this:
var data = [{field:"Data",type:"date"}, {field:"Numero",type:"number"}];
var columns = {};
var index = 0;
$.each(data, function() {
columns[index] = {
field : this.field,
type : this.type
};
index++;
});
console.log(columns);
If anyone comes looking to create a similar JSON, just without using cart as an array, here goes:
I have an array of objects myArr as:
var myArr = [{resourceType:"myRT",
id: 1,
value:"ha"},
{resourceType:"myRT",
id: 2,
value:"he"},
{resourceType:"myRT",
id: 3,
value:"Li"}];
and I will attempt to create a JSON with the following structure:
{
"1":{"resourceType":"myRT","id":"1","value":"ha"},
"2":{"resourceType":"myRT","id":"2","value":"he"},
"3":{"resourceType":"myRT","id":"3","value":"Li"}
}
you can simply do-
var cart = {};
myArr.map(function(myObj){
cart[myObj.id]= myObj;
});
function addValueInObject(value, object, key) {
var addMoreOptions = eval('{"' + key + '":' + value + '}');
if(addMoreOptions != null) {
var textObject = JSON.stringify(object);
textObject = textObject.substring(1,textObject.length-1);
var AddElement = JSON.stringify(addMoreOptions);
object = eval('{' + textObject +','+ AddElement.substring(1,AddElement.length-1) + '}');
}
return object;
}
addValueInObject('sdfasfas', yourObject, 'keyname');
OR:
var obj = {'key':'value'};
obj.key2 = 'value2';
For anyone still looking for a solution, I think that the objects should have been stored in an array like...
var element = {}, cart = [];
element.id = id;
element.quantity = quantity;
cart.push(element);
Then when you want to use an element as an object you can do this...
var element = cart.find(function (el) { return el.id === "id_that_we_want";});
Put a variable at "id_that_we_want" and give it the id of the element that we want from our array. An "elemnt" object is returned. Of course we dont have to us id to find the object. We could use any other property to do the find.
My proposition is to use different data structure that proposed already in other answers - it allows you to make push on card.elements and allow to expand card properties:
let card = {
elements: [
{"id":10,"quantity":1}
],
//other card fields like 'owner' or something...
}
card.elements.push({"id":22,"quantity":3})
console.log(card);
push is an method of arrays , so for object you can get the index of last element ,and you can probably do the same job as push for object as below
var lastIndex = Object.keys(element)[Object.keys(element).length-1];
then add object to the new index of element
element[parseInt(lastIndex) +1] = { id: id, quantity: quantity };
if you not design to do loop with in JS e.g. pass to PHP to do loop for you
let decision = {}
decision[code+'#'+row] = event.target.value
this concept may help a bit
This is an old question, anyway today the best practice is by using Object.defineProperty
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
In case anyone else needs this, I finally found a good way to add objects or arrays of objects:
var myobj = {}
// These two options only work for single-valued keys, not arrays or objects
myobj["a"] = 1
myobj.b = 2
// This one works for everyting:
Object.assign(myobj, {"key": "value"}); // single-value
// Add object
Object.assign(myobj, {"subobj":
{
"c": 3
}
});
// Add array of objects
Object.assign(myobj, {"subarr":
[
{
"d": 4,
},
{
"e": 5
}
]
});
var newObject = {element:{"id":10,"quantity":1}};
console.log(newObject);

Categories