I have Array objects like below , How to convert this format into Array of objects and remove key.
{
"9417702107": {
"name": "Sunny",
"phone": "9417702107",
"exists": true
},
"8826565107": {
"name": "Gurwinder",
"phone": "8826565107",
"exists": true
}
}
How to convert this into below format using javascript:
[{
"name": "Sunny",
"phone": "9417702107",
"exists": true
}, {
"name": "Gurwinder",
"phone": "8826565107",
"exists": true
}]
Use a simple loop:
array = [];
for (var key in obj) {
array.push(obj[key]);
}
As in the other answer, there's no guarantee that the elements of the array will be in the same order as in the object.
simply try this
var output = Object.keys(obj).map(function(key){
return obj[key];
})
Note that there is no guarantee that order of items in output array will be same as in the order key-values in your object as you see it.
if the order is important, then put an new attribute called order in the object itself
var obj {
"9417702107":
{
"name": "Sunny",
"phone": "9417702107",
"exists": true,
"order_sequence" : 1
},
"8826565107": {
"name": "Gurwinder",
"phone": "8826565107",
"exists": true,
"order_sequence" : 1
}
}
and then after converting to array, you can sort on the order_sequence
var output = Object.keys(obj).map(function(key){
return obj[key];
}).sort( function(a,b){
return a.order_sequence - b.order_sequence;
});
Use Object.keys and for-cycle.
var keys = Object.keys(input), output = [];
for (var i = 0, length = keys.length; i < length; ++i)
ouptput.push(input[keys[i]]);
console.log(output);
Some tips:
- Cycles in this case gives move performance than map function, because in today JS engines: fewer functions calls, greater performance.
- For-each (for (var k in input) {}) is slower than Object.keys and cycle for/while.
This is acceptable for today implementation Google V8 and Mozilla SpiderMonkey.
Related
I'm using Vue, lodash, etc.
{
"street": {
"id": "1",
"streetName": "test",
"buildings": [
{
"id": "1",
"buildingName": "test"
}
]
}
}
I have a setup similar to this. This is a singular object, I basically have an array of these.
All I get is a building.id value.
From it, I need to be able to find the building it belongs to, and there isn't any direct list of buildings for me to access.
Currently
I'm using a nested loop to loop through each site until I find the one that has a building with that id. I don't know if I'm doing it correctly, it doesn't feel correct.
for(var i = 0; i < streets.length; i++){
for(var x = 0; x < streets[i].buildings.length;x++){
if(streets[i].buildings[x].id == '2aec6bed-8cdd-4043-9041-3db4681c6d08'){
}
}
}
Any tips? Thanks.
You can use a combination of filter and some methods, like this:
var result = streets.filter(function(s) {
return s.street.buildings.some(function(b) {
return b.id === searchedId;
});
});
Using .some() method will return true if any building of the iterated buildings has the searchedId.
Using .filter() will filter the streets array to return only street object where the call of some() method on its buildings will return true, in other words which meets the condition of having an idequal to searchedId.
Demo:
var streets = [{
"street": {
"id": "1",
"streetName": "test",
"buildings": [{
"id": "1",
"buildingName": "test"
}]
}
}, {
"street": {
"id": "1",
"streetName": "test",
"buildings": [{
"id": '2aec6bed-8cdd-4043-9041-3db4681c6d08',
"buildingName": "test"
}]
}
}];
var searchedId = '2aec6bed-8cdd-4043-9041-3db4681c6d08';
var result = streets.filter(function(s) {
return s.street.buildings.some(function(b) {
return b.id === searchedId;
});
});
console.log(result);
If you're trying to get all the buildings in all streets by a buildingId, this solves the problem:
streetsList.map(streetItem => streetItem.street.buildings.find(building => building.id === searchedBuildingId)).filter(v => v);
.filter(v => v) is for filtering out falsy values since we want a clean result here.
If there can be more than a single building in a street with the same id, then use .some instead of .find in the example.
Presumably you have a streets object that contains street objects, like:
var streets = [
street :{ ... },
street :{ ... },
...
];
So you need to step into each street and iterate over the buildings. A for loop should be fairly efficient since it can return as soon as it finds the building. I don't think any of the built-in looping methods will do that.
The code in the OP won't work, as streets[i].buildings must be streets[i].streets.buildings and if(streets[i].buildings[x].id must be if(streets[i].street.buildings[x].id.
Below is a working for loop version, there's also a version using recent Array methods which are very much slower even on a very small dataset. According to jsperf, the for loop version is about 100 times faster in Safari, 10 times faster in Firefox and 50 times faster in Chrome.
I also think the for loop code is much more readable and therefore maintainable.
var streets = [{
"street": {
"id": "1",
"streetName": "test",
"buildings": [{
"id": "1",
"buildingName": "test"
}, {
"id": "2",
"buildingName": "test"
}]
}
}, {
"street": {
"id": "2",
"streetName": "test",
"buildings": [{
"id": "3",
"buildingName": "test"
}]
}
}
];
function getBldById(data, id) {
for (var i=0, iLen=streets.length; i<iLen; i++) {
var street = streets[i].street;
for (var j=0, jLen=street.buildings.length; j<jLen; j++) {
if (street.buildings[j].id == id) {
return street.buildings[j];
}
}
}
return null;
}
console.log(getBldById(streets, '1'));
function getBldById2(data, id) {
return data.map(streetObj =>
streetObj.street.buildings.find(building =>
building.id === id)
).filter(v => v)[0];
}
console.log(getBldById2(streets, '1'));
You might be missing street property, right?
I mean it should be: streets[i].street.buildings[x].id
I get 100 objects (JSON) from a website, which is build like this.
"object" : [{
"id": 12243,
"name": 'Carl',
"text": 'subheader',
"tags": ["cars","child", "blue"],
...
},
{
"id": 12245,
"name": 'Dark',
"text": 'subheader',
"tags": ["cars"],
...
}
...
]
I want to get only which has the tag child. How can I do it?
You could try something like this:
var objectsWithChild = json.object.filter(function(o){
return o.tags.includes("child");
});
where json is your json string.
Using Array.prototype.filter()
var objs = [{
"id": 12243,
"name": 'Carl',
"text": 'subheader',
"tags": ["cars","child", "blue"]
},
{
"id": 12245,
"name": 'Dark',
"text": 'subheader',
"tags": ["cars"]
}]
var objsWithTags = objs.filter(obj => obj.tags.indexOf('child') > -1);
console.log(objsWithTags);
Christos has a cleaner way to do it, but this way might be clearer to a beginner. One way to do it would be to use nested for loops.
var myObjects = []
for (var i = 0; i < data.object.length; i++) {
var ob = data.object[i];
for (var j = 0; j < ob.tags.length; j++) {
if (ob.tags[i] === "child") {
myObjects.push(ob);
}
}
}
There are probably multiple ways to implement this.
But the main ideas are mostly the same.
Here in textual form:
Define a container (an array for example) for your matched objects.
Loop through all objects.
Loop through all entries of your array "tags".
Check if you find your desired value "child".
Remember your found object by adding it to your container (array).
I have a response from a web service and want to replace some values in the response with my custom values.
One way is to write a tree traverser and then check for the value and replace with my custom value
so the response is some what like this:
[
{
"name": "n1",
"value": "v1",
"children": [
{
"name": "n2",
"value": "v2"
}
]
},
{
"name": "n3",
"value": "v3"
}
]
now my custom map is like this
const map = {
"v1": "v11",
"v2": "v22",
"v3": "v33"
};
All I want is
[
{
"name": "n1",
"value": "v11",
"children": [
{
"name": "n2",
"value": "v22"
}
]
},
{
"name": "n3",
"value": "v33"
}
]
I was thinking if I could stringify my response and then replace values using a custom build regex from my map of values.
Will it be faster as compared to tree traverser?
If yes, how should I do that?
somewhat like this
originalString.replace(regexp, function (replacement))
The tree traversal is faster
Note that some things could be done more efficiently in the regex implementation but I still think there are some more bottlenecks to explain.
Why the regex is slow:
There are probably many more reasons why the regex is slower but I'll explain at least one significant reason:
When you're using regex to find and replace, you're using creating new strings every time and performing your matches every time. Regex expressions can be very expensive and my implementation isn't particularly cheap.
Why is the tree traversal faster:
In the tree traversal, I'm mutating the object directly. This doesn't require creating new string objects or any new objects at all. We're also not performing a full search on the whole string every time as well.
RESULTS
run the performance test below. The test using console.time to record how long it takes. See the the tree traversal is much faster.
function usingRegex(obj, map) {
return JSON.parse(Object.keys(map).map(oldValue => ({
oldValue,
newValue: map[oldValue]
})).reduce((json, {
oldValue,
newValue
}) => {
return json.replace(
new RegExp(`"value":"(${oldValue})"`),
() => `"value":"${newValue}"`
);
}, JSON.stringify(obj)));
}
function usingTree(obj, map) {
function traverse(children) {
for (let item of children) {
if (item && item.value) {
// get a value from a JS object is O(1)!
item.value = map[item.value];
}
if (item && item.children) {
traverse(item.children)
}
}
}
traverse(obj);
return obj; // mutates
}
const obj = JSON.parse(`[
{
"name": "n1",
"value": "v1",
"children": [
{
"name": "n2",
"value": "v2"
}
]
},
{
"name": "n3",
"value": "v3"
}
]`);
const map = {
"v1": "v11",
"v2": "v22",
"v3": "v33"
};
// show that each function is working first
console.log('== TEST THE FUNCTIONS ==');
console.log('usingRegex', usingRegex(obj, map));
console.log('usingTree', usingTree(obj, map));
const iterations = 10000; // ten thousand
console.log('== DO 10000 ITERATIONS ==');
console.time('regex implementation');
for (let i = 0; i < iterations; i += 1) {
usingRegex(obj, map);
}
console.timeEnd('regex implementation');
console.time('tree implementation');
for (let i = 0; i < iterations; i += 1) {
usingTree(obj, map);
}
console.timeEnd('tree implementation');
Will it be faster as compared to tree traverser?
I don't know. I think it would depend on the size of the input, and the size of the replacement map. You could run some tests at JSPerf.com.
If yes, how should I do that?
It's fairly easy to do with a regex-based string replacement if the values you are replacing don't need any special escaping or whatever. Something like this:
const input = [
{
"name": "n1",
"value": "v1",
"children": [
{
"name": "n2",
"value": "v2"
}
]
},
{
"name": "n3",
"value": "v3"
}
];
const map = {
"v1": "v11",
"v2": "v22",
"v3": "v33"
};
// create a regex that matches any of the map keys, adding ':' and quotes
// to be sure to match whole property values and not property names
const regex = new RegExp(':\\s*"(' + Object.keys(map).join('|') + ')"', 'g');
// NOTE: if you've received this data as JSON then do the replacement
// *before* parsing it, don't parse it then restringify it then reparse it.
const json = JSON.stringify(input);
const result = JSON.parse(
json.replace(regex, function(m, key) { return ': "' + map[key] + '"'; })
);
console.log(result);
definitely traverser go faster as string replace means travels against each characters in the final string as opposed to iterator that can skips no necessarily item.
I'm asking here as I can see this website the most one can help in this
I have an output value in JASON format as the following:
{
"total": 16,
"members": [{
"id": 4,
"name": "Blade11",
"descriptors": {
"os": "Windows 2012 / WS2012 R2"
},
"FCPaths": [{
"wwn": "50060B0000C27208",
"hostSpeed": 0
}, {
"wwn": "50060B0000C2720A",
"hostSpeed": 0
}],
"iSCSIPaths": [],
"persona": 11,
"links": [{
"href": "https://3par:8080/api/v1/hostpersonas?query=\"wsapiAssignedId EQ 11\"",
"rel": "personaInfo"
}],
"initiatorChapEnabled": false,
"targetChapEnabled": false
}, {
"id": 6,
"name": "Blade4",
"descriptors": {
"os": "VMware (ESXi)"
},
"FCPaths": [{
"wwn": "50060B0000C27216",
"hostSpeed": 0
}, {
"wwn": "50060B0000C27214",
"hostSpeed": 0
}],
"iSCSIPaths": [],
"persona": 8,
"links": [{
"href": "https://3par:8080/api/v1/hostpersonas?query=\"wsapiAssignedId EQ 8\"",
"rel": "personaInfo"
}],
"initiatorChapEnabled": false,
"targetChapEnabled": false
}
what I want is, to parse this output for retrieving an output parameter with the name object only in a list or array of string
for example Names = Blade11, Blade4,....
if you can see in the Json output we have all the names under "members", then each one is another array of values, I want to retrieve only names
thanks
If this JSON is string first you have to parse it
var json = JSON.parse('here is your JSON string');
Than you can access to it properties like you work with object
var names = json.members.map(function(member) {
return member.name;
});
Since you already have JSON format, you can use an array method on the member key of your JSON object to iterate through each array item.
var names = [];
object_name.members.forEach((arrItem) => {
names.push(arrItem.name);
}
or
namesArray = object_name.members.map((arrItem) => {
return arrItem.name;
}
You could use Array#map for iterating all elements of the array and return only the name property.
If you have a JSON string, you need to parse it in advance for getting an object, like
object = JSON.parse(jsonString);
var jsonString = '{"total":16,"members":[{"id":4,"name":"Blade11","descriptors":{"os":"Windows 2012 / WS2012 R2"},"FCPaths":[{"wwn":"50060B0000C27208","hostSpeed":0},{"wwn":"50060B0000C2720A","hostSpeed":0}],"iSCSIPaths":[],"persona":11,"links":[{"href":"https://3par:8080/api/v1/hostpersonas?query=\\"wsapiAssignedId EQ 11\\"","rel":"personaInfo"}],"initiatorChapEnabled":false,"targetChapEnabled":false},{"id":6,"name":"Blade4","descriptors":{"os":"VMware (ESXi)"},"FCPaths":[{"wwn":"50060B0000C27216","hostSpeed":0},{"wwn":"50060B0000C27214","hostSpeed":0}],"iSCSIPaths":[],"persona":8,"links":[{"href":"https://3par:8080/api/v1/hostpersonas?query=\\"wsapiAssignedId EQ 8\\"","rel":"personaInfo"}],"initiatorChapEnabled":false,"targetChapEnabled":false}]}',
object = JSON.parse(jsonString),
array = object.members.map(function (a) { return a.name; });
console.log(array);
I have a working version of a function to loop through a single array in a JSON object, e.g.
[{
"Name": "John",
"Surname": "Johnson"
}, {
"Name": "Peter",
"Surname": "Johnson"
}]
sample function:
function FindName(NameToFind, data1) {
objData = JSON.parse(data1);
for (var i = 0; i < objData.length; i++) {
var Name = objData[i].Name;
if (Name == NameToFind) {
alert("found!");
}
}
}
Now I need to change this function to allow for either single OR multiple arrays e.g.
{
"Table1": [{
"Name": "John",
"Surname": "Johnson"
}, {
"Name": "Peter",
"Surname": "Johnson"
}],
"Table2": [{
"Name": "Sarah",
"Surname": "Parker"
},
{
"Name": "Jonah",
"Surname": "Hill"
}
]
}
Is there a way to determine whether the object has 1 array (like in first example) or more than one arrays (like in 2nd example), and any advice/guidance on how to extend the function to be able to loop through all the items whether it has 1 array or multiple arrays?
Your first object is an array, the second one isn't.
You can test if your argument is an array, or even just test
if (objData[0]) // that's an array
EDIT :
if you want to iterate over all properties of a (just json decoded) object, when it's not an array, you can do this :
for (var key in objData) {
var value = objData[key];
// now use the key and the value
// for example key = "Table1"
// and value = [{"Name":"John","Surname":"Johnson"}, ... ]
}