Extract only values from JSON object in javascript without using a loop - javascript

is there a "Nice" way to get all the values out of a json object (I don't care about the keys) - just get the values into array,
without using a loop ?
(lang is Javascript)

It depends on how you define "loop".
You can extract the properties with Object.keys and then map them to their values.
… it's still essentially a loop under the hood though.
var json = `{ "foo": 1, "bar": 2, "baz": 3 }`;
var obj = JSON.parse(json);
var values = Object.keys(obj).map(function (key) { return obj[key]; });
console.log(values);
With weaker browser support you could use the values method.
var json = `{ "foo": 1, "bar": 2, "baz": 3 }`;
var obj = JSON.parse(json);
var values = Object.values(obj);
console.log(values);

I think you are looking for Object.values() function, just pass the object to the values method of Object as first param. That's it!
Object.values({something: 'lol'});
> ["lol"]

Recursively extract as text
Yes, this is a loop but the underlying methods you are calling such as Object.values or arr.map are still loops. I found this useful for extracting text out of a json object for full text search in particular and thought it useful as I came here initially needing this but the answers only touched the surface as json is recursive in nature.
function textFromJson(json) {
if (json === null || json === undefined) {
return '';
}
if (!Array.isArray(json) && !Object.getPrototypeOf(json).isPrototypeOf(Object)) {
return '' + json;
}
const obj = {};
for (const key of Object.keys(json)) {
obj[key] = textFromJson(json[key]);
}
return Object.values(obj).join(' ');
}

With ES2017 you have Object.values(). You can polyfill it also.
Only you need is transform JSON to JavaScript object and call Object.values(). The result is an array of values.
var obj = JSON.parse(jsonData);
var result = Object.values(obj);

If you pass a function to JSON.parse, it will be called each time a value is parsed:
function get_values(json) {
let values = []
JSON.parse(json, (key,value)=>{ values.push(value) })
return values
}
ex:
get_values(`{"a":1, "b":[true, false], "c":3}`)
// returns a list of:
• 1
• true
• false
• [true, false]
• 3
• {a:1, b:[true, false], c:3}
Note: If you don't consider the full object to be a "value", just remove the last item.

Related

Dynamically create a nested JavaScript object with unknown keys

Let's say I have two arrays which are returned in a response from a REST call. For simplification I defined them hard-coded as keys and subKeys in the following example code.
From these arrays I'd like to create a nested object which, when outputted as a JSON string, looks like this:
Target JSON
{
"key1": {
"subKey1": "someValue"
},
"key2": {
"subKey2": "someValue"
},
"key3": {
"subKey3": "someValue"
}
}
Code sample
var keys = ["key1", "key2", "key3"]; // These come from a REST response
var subKeys = ["subKey1", "subKey2", "subKey3"]; // These come from a REST response
var targetObj = {}
for (const key in keys) {
targetObj[key] = {}
for (const subKey in subKeys) {
targetObj[key][subKey] = "someValue";
}
}
console.log(JSON.stringify(targetObj, null, 2));
While this gives me the correct behavior in my application I have the impression that there might be simpler approaches to achieve the same result, either in "vanilla" JavaScript or ES6? What bothers me here is that I define an empty object in each run of the for loop.
Your code does not produce the example output you said you want. It will put all 3 subkeys under each key, not one per key. Also you end up with numeric keys, not the key names.
var keys = ["key1", "key2", "key3"]; // These come from a REST response
var subKeys = ["subKey1", "subKey2", "subKey3"]; // These come from a REST response
var targetObj = {}
for (let i=0; i<keys.length; i++) {
const key = keys[i];
targetObj[key] = { [subKeys[i]]: "someValue" };
}
console.log(JSON.stringify(targetObj, null, 2));
First you were using "in" instead of "of" in the for-loop, and secondly you were not using the same index to find the subkey.
To avoid creating an empty object you can use this syntax:
{ [variable]: "value" }
This creates the object with the variable value as the key, and a string as the value. Putting the variable name in square brackets tells it to use the variable value rather than its name. Saying { variable: "value" } wouldn't work because the key would be "variable" not the value of variable.
Just use Array.prototype.reduce method:
const keys = ["key1", "key2", "key3"];
const subKeys = ["subKey1", "subKey2", "subKey3"];
const result = keys.reduce((acc, key, index) =>
({ ...acc, [key]: { [subKeys[index]]: 'someValue' } })
, {});
Note, this works only if keys and subKeys arrays are synced and their indexes are consistent with each other.

Javascript: Convert a JSON string into ES6 map or other to preserve the order of keys

Is there a native (built in) in ES6 (or subsequent versions), Javascript or in TypeScript method to convert a JSON string to ES6 map OR a self-made parser to be implemented is the option? The goal is to preserve the order of the keys of the JSON string-encoded object.
Note: I deliberately don't use the word "parse" to avoid converting a JSON string first to ECMA script / JavaScript object which by definition has no order of its keys.
For example:
{"b": "bar", "a": "foo" } // <-- This is how the JSON string looks
I need:
{ b: "bar", a: "foo" } // <-- desired (map version of it)
UPDATE
https://jsbin.com/kiqeneluzi/1/edit?js,console
The only thing that I do differently is to get the keys with regex to maintain the order
let j = "{\"b\": \"bar\", \"a\": \"foo\", \"1\": \"value\"}"
let js = JSON.parse(j)
// Get the keys and maintain the order
let myRegex = /\"([^"]+)":/g;
let keys = []
while ((m = myRegex.exec(j)) !== null) {
keys.push(m[1])
}
// Transform each key to an object
let res = keys.reduce(function (acc, curr) {
acc.push({
[curr]: js[curr]
});
return acc
}, []);
console.log(res)
ORIGINAL
If I understand what you're trying to achieve for option 2. Here's what I came up with.
https://jsbin.com/pocisocoya/1/edit?js,console
let j = "{\"b\": \"bar\", \"a\": \"foo\"}"
let js = JSON.parse(j)
let res = Object.keys(js).reduce(function (acc, curr) {
acc.push({
[curr]: js[curr]
});
return acc
}, []);
console.log(res)
Basically get all the keys of the object, and then reduce it. What the reducer function convert each keys to an object
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
More details : http://2ality.com/2015/08/es6-map-json.html
use for in loop
let map = new Map();
let jsonObj = {a:'a',b:'b',c:'c'}
for (let i in jsonObj){
map.set(i,jsonObj[i]);
}
btw, i saw the comment below and i think map is not ordered because you use key to achieve data in map, not the index.

java script to transform json data

my survey output is like
{"a":"1","b":"2","c":"1","d":"0","e":"please improve","Id":"789"} when it reaches the jsp, and i would like to change 0 to good, 1 to bad and 2 to ok, which are the outputs of a,b,c,d .how can we do it using foreach function.
Something like this?
var input = {"a":"1","b":"2","c":"1","d":"0","e":"please improve","Id":"789"};
var mapvals = {"0":"good", "1":"bad", "2":"ok"};
var newObject = Object.keys(input).reduce(function(previous, current) {
previous[current] = mapvals[input[current]] || input[current];
return previous;
}, {});
console.log(newObject);
Which gives:
{
a: "bad",
b: "ok",
c: "bad",
d: "good",
e: "please improve",
Id: "789"
}
You could do it manually with a forEach function if you really wanted... but I'll leave that to you.
foreach() and map() only work on arrays, so they can't be used directly on your object. You'll have to use the keys() or entries() functions first to get the fields in the object as an array.
Unfortunately Object.entries() currently only works in Firefox(*). However, as it happens, keys() produces simpler code anyway.
var input = {"a":"1","b":"2","c":"1","d":"0","e":"please improve","Id":"789"};
var mapvals = {"0":"good", "1":"bad", "2":"ok"};
var output = {};
Object.keys(input).forEach(function(key) {
output[key] = mapvals[input[key]] || input[key];
});
console.log(output);
(*) It's available in Chrome also, but only behind a configuration flag.
you could convert the values when serializing the object. Before you send the json to the backend:
var data = {"a":"1","b":"2","c":"1","d":"0","e":"please improve","Id":"789"};
var mapvals = {"0":"good", "1":"bad", "2":"ok"};
var json = JSON.stringify(data, (key, value) => key && value in mapvals? mapvals[value]: value);
json:
{"a":"bad","b":"ok","c":"bad","d":"good","e":"please improve","Id":"789"}
you can also add further "filter" to only apply this logic to some keys
also works with more complex data, like the Array of items like that, that you mentioned.
var data = [
{"a":"0","b":"2","c":"0","d":"0","e":" ","id":"456"},
{"a":"0","b":"0","c":"0","d":"0","e":"test","i‌​d":"123"},{"a":"0","‌​b":"2","c":"0","d":"‌​0","e":"please test ","id":"456"},
{"a":"0","b":"2","c":"0","d":"0","e":" ","id":"456"},
{"a":"0","b":"1","c":"1","d":"0","e":" ","id":"456"},
{"a":"2","b":"2","c":"2","d":"2","e":" ","id":"789"},
{"a":"1","b":"1","c":"1","d":"1","e":"survey ","id":"789"},
{"a":"1","b":"1","c":"2","d":"2","e":"1234567"‌​,"id":"789"},
{"a":"0‌​","b":"0","c":"0","d‌​":"0","e":" ","id":"234"}
];
var mapvals = {"0":"good", "1":"bad", "2":"ok"};
var json = JSON.stringify(data, (key, value) => key && value in mapvals? mapvals[value]: value);
json:
[{"a":"good","b":"ok","c":"good","d":"good","e":" ","id":"456"},{"a":"good","b":"good","c":"good","d":"good","e":"test","id":"123"},{"a":"good","b":"ok","c":"good","d":"good","e":"please test ","id":"456"},{"a":"good","b":"ok","c":"good","d":"good","e":" ","id":"456"},{"a":"good","b":"bad","c":"bad","d":"good","e":" ","id":"456"},{"a":"ok","b":"ok","c":"ok","d":"ok","e":" ","id":"789"},{"a":"bad","b":"bad","c":"bad","d":"bad","e":"survey ","id":"789"},{"a":"bad","b":"bad","c":"ok","d":"ok","e":"1234567","id":"789"},{"a":"good","b":"good","c":"good","d":"good","e":" ","id":"234"}]

js array to json but some value disappear

window.onload = function() {
var arr = new Array;
var jsonObj = {
"123": "234"
};
arr['v'] = "234";
arr[0] = jsonObj;
arr[1] = jsonObj;
console.log(JSON.stringify(arr));
}
The above code result is :
[{"123":"234"},{"123":"234"}]
I don't know why the arr['v'] disappeared?
Object and Array are not parsed to JSON the same way.
an Array will only include the numeric keys, and an Object will include all of its keys:
var Arr = [], Obj ={};
Arr[0] = Obj[0] = 'a';
Arr[1] = Obj[2] = 'b';
Arr['key'] = Obj['key'] = 'c';
console.log(JSON.stringify(Arr));
console.log(JSON.stringify(Obj));
so in your case, you could simply use an Onject instead of an array:
var arr = new Object;
var jsonObj = {"123":"234"};
arr['v'] = "234";
arr[0] = jsonObj;
arr[1] = jsonObj;
console.log(JSON.stringify(arr));
Actually, JSON.stringify will ignore non-numeric keys in Array during the Array JSON serialization. From the latest ECMA Spec, in section "24.3.2.4 Runtime Semantics: SerializeJSONArray ( value )", we know JSON.stringify only utilizes length of Array and related numeric keys to do the serialization, and Array length will not be affected by its non-numeric keys. So it is now clear why 'v' (non-numeric keys) disappear in your final result.
You can't use a string as an array index, unless it is a string representation of an integer.
Therefore, arr['v'] has no meaning.
This stackoverflow question goes into more detail, but the relevant part:
Yes, technically array-indexes are strings, but as Flanagan elegantly
put it in his 'Definitive guide':
"It is helpful to clearly distinguish an array index from an object
property name. All indexes are property names, but only property names
that are integers between 0 and 232-1 are indexes."
In JavaScript, basically two types of array, Standard array and associative array. Standard array is defined by [], so 0 based type indexes. And in associative array is defined by {}, in this case you can define string as keys. So in your code you are using both is single array, that's not acceptable. So define the another array if you want strings keys.

Arrays with Objects as Key Values in Javascript

I have the following requirement. I have a pair of integers which is to act as keys and another pair of integers which should act as values. That is:
obj[{key1:12,key2:23}]=[2,3];
obj[{key1:12,key2:22}]=[4,3];
obj[{key1:34,key2:12}]=[4,33];
Also finally when the population of this list is over, I would like to sequentially access the elements of the object/array.
Now it is my understanding that for such arrays which take an object as key, they are known as associative arrays and Javascript doesn't support them..
The following will be the operations I will perform on this structure :
Insertion: I will have keys like (2,3) or (2,4) which I would like to insert into the array with a new keyvalue pair such as [1,2],
Lookup : I may have a key pair like (2,3) which is already inserted into this array and I would like to get it back so that I can modify it.
That is something like:
if(obj[{key1:2,key2:3}])
obj[{key1:2,key2:3}]=[2,5];
else
obj[{key1:2,key2:3}]=[2,-1];
Any suggestions as to how I can implement this in Javascript?
EDIT: These are the two things I tried:
First I made it as an array of objects. This approach didn't work because from looking around, I knew that in such cases, Javascript will call the toString method to get the string equivalent of the object which it will then use an index.
Second, I tried to do an object with object keys containing sub-objects. Something along the lines of this answer: Answer. However I am not sure how to get sequential access to all the elements after I am done with the insertion phase.
You're probably not going to like this much, but it'll at least give you a stable key:
obj[JSON.stringify({key1:12,key2:23})]=[2,3];
So, the big problem is that in an object the 'key' (really, the 'property') must be a string, or be able to be stringified. In your examples, {key1:12,key2:23} will always be stringified to [object Object]. So you'll never get a unique key. The only way to get that unique key is to really serialize it, such as by using the JSON.stringify method.
Note that on IE8 I think you have to include a JSON class.
Here is an object oriented way to do it:
// Constructor
function AssociativeArray() {
this.length = 0;
}
// Add or set value
AssociativeArray.prototype.set = function(key, value) {
key = key.key1+'|'+key.key2;
if(!this[key]) {
this.length++;
}
this[key] = value;
};
// Lookup
AssociativeArray.prototype.get = function(key) {
return this[key.key1+'|'+key.key2];
};
AssociativeArray.prototype.toString = function() {
var k, arr = [];
for(k in this) {
if(this.hasOwnProperty(k) && k !== 'length') {
arr.push(this[k]);
}
}
return arr;
};
// Create Associative Array
var arr = new AssociativeArray();
// empty array
console.log(arr.toString(), 'length='+arr.length); // [] length=0
// add value
arr.set({key1:1, key2:2}, [1,1]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1]] length=1
// add value
arr.set({key1:2, key2:1}, [2,2]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [2,2]] length=2
// set value
arr.set({key1:2, key2:1}, [3,3]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [3,3]] length=2
// lookup and set
if(arr.get({key1:2, key2:3})) {
arr.set({key1:2, key2:3}, [2,5]);
} else {
arr.set({key1:2, key2:3}, [2,-1]);
}
console.log(arr.toString(), 'length='+arr.length); // [[1, 1], [3, 3], [2, -1]] length=3
Fiddle here: http://jsbin.com/ohOwala/3/edit
You could use a bidimensional array
var arr = [];
arr[2] = [];
arr[2][3] = [1, 2];
Or you could use an object and access the pairs using the object properties names
obj = {
_2_3: [1, 2],
_2_1: [4, 1],
_1_2: [3, 2]
};
and access them like this obj["_2_3"] or this obj._2_3
or maybe you could nest em
obj = {
_1: {
_2: [2,1]
}
};
so you could access them like this obj["_1"]["_2"]
or maybe this
obj = {
1: {
2: [2,1]
}
};
But you will be forced to use associatve array notation obj["1"]["2"]
and as far as i know using the associative array like way for accessing objects properties isnt a good practice
I asked where the objects {key1:2,key3:2} came from because if you have control over it you can implement a toString method for those types that will take care of the Object to string conversion so it can be used as a property name.
//define keypair object type
var MyKeyPair = function(key1,key2){
this.key1=key1;
this.key2=key2;
};
//define tostring for this type
// later obj[aKeyPairInstance] will
// invoke the toString method
// if you don't do this then [Object object]
// would be returned for toString
MyKeyPair.prototype.toString=function(){
//since you know there is only going to be key1 and key2
// you could just:
// return this.key1+":"+this.key2;
//Here follows a more general approach but it'll cost
// you more cpu time, if working with very large amounts
// of data use the shorter version.
var ret=[];
for(thing in this){
if(this.hasOwnProperty(thing)){
ret.push(thing);
ret.push(":");
ret.push(this[thing]);
ret.push(",");
}
}
return ret.join("");
};
// make a bunch of keyPair objects
var keys = [
new MyKeyPair(21,33),
new MyKeyPair(22,34),
new MyKeyPair(23,35),
new MyKeyPair(24,36)
];
//create an object and give it properties
// based on the tostring value of the keypairs
var obj={};
for(var i = 0,len=keys.length;i<len;i++){
obj[keys[i]]=[keys[i].key1,keys[i].key2];
};
console.log(obj);//<=this would not log any usefull info in IE
//Use Chrome, Firefox, Opera or any other browser instead

Categories

Resources