This is my JSON string
[{"$id":"1","GeoName":"EAST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206},{"$id":"2","GeoName":"WEST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206}]"
This is my JSONobject before Stringyfying
**MyObj:**
0:Object
$id:"1"
Value1:18.44377295716579
GeoName:"EAST"
Value2:87.88221970554928
Value3:16.732108234801206
Value4:90.71955219607294
1:Object
$id:"2"
Value1:18.44377295716579
GeoName:"WEST"
Value2:87.88221970554928
Value3:16.732108234801206
Value4:90.71955219607294
Is there a way to round off all the values(or even individually value1,value2...) upto 2 decimal points in each every object of my JSON?
Like
0:Object
$id:"1"
Value1:18.44
GeoName:"EAST"
Value2:87.89
Value3:16.73
Value4:90.72
1:Object
$id:"2"
Value1:18.44
GeoName:"WEST"
Value2:87.89
Value3:16.73
Value4:90.71
I have tried using
Obj = JSON.parse(JSON.stringify(MyObj, function (GeoName, Value1) {
return Value1.toFixed ? Number(Value1.toFixed(2)) : Value1;
}));
Which did not work for me.
Is there a way i can achieve this by tweaking the above line of code or is there a better approach to solve this issue?
Edit1(After the approach suggested by wostex)
var numKeys = ['ShareValue','ReachValue','DepthValue','WidthValue'];
MyObj=Obj.map(e => Object.assign(e,Object.keys(e).filter(k => numKeys.includes(k)).map(v => Object.assign({[v]: parseFloat(e[v]).toFixed(2)}))))
This is How my object is looking like
0:Object
0:Object
ReachValue:87.88
1:Object
DepthValue:16.73
2:Object
ShareValue:18.44
3:Object
WidthValue:90.71
$id:"1"
ShareValue:18.44377295716579
GeoName:"EAST"
ReachValue:87.88221970554928
DepthValue:16.732108234801206
WidthValue:90.71955219607294
Edit2
Obj = JSON.parse(JSON.stringify(BubbleObj));
var numKeys = ['ShareValue','ReachValue','DepthValue','WidthValue'];
var MyObj=Obj.map(e => Object.assign(e,Object.keys(e).filter(k => numKeys.includes(k)).map(v => Object.assign({[v]: parseFloat(e[v]).toFixed(2)}))))
Here Obj has the JSON string from the first line of the question and BubbleObj has the Object which i mentioned as MyObj in the question.
The easy way is just to use map - and as long as your Value1-4 are always called that
var input = [{"$id":"1","GeoName":"EAST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206},{"$id":"2","GeoName":"WEST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206}];
var output = input.map(function(e) {
return {
$id: e.$id,
GeoName: e.GeoName,
Value1: Math.round(e.Value1*100) /100,
Value2: Math.round(e.Value2*100) /100,
Value3: Math.round(e.Value3*100) /100,
Value4: Math.round(e.Value4*100) /100
}
});
console.log(output);
If you dont want to hardcode it, you could look for any key starting Value - its a little more complex.
var input = [{"$id":"1","GeoName":"EAST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206},{"$id":"2","GeoName":"WEST","Value2":87.88221970554928,"Value4":90.71955219607294,"Value1":18.44377295716579,"Value3":16.732108234801206}];
var output = input.map(function(e) {
return Object.keys(e).reduce(function(p,n){
if(n.startsWith("Value"))
p[n] = Math.round(e[n]*100)/100;
else
p[n] = e[n];
return p;
},{})
});
console.log(output);
BTW you have duplicated keys 'Value3' in your first string, other than that you can do the following:
var j = [{"$id":"1","GeoName":"EAST","ShareValue":87.88221970554928,"ReachValue":90.71955219607294,"DepthValue":18.44377295716579,"WidthValue":16.732108234801206},{"$id":"2","GeoName":"WEST","ShareValue":87.88221970554928,"ReachValue":90.71955219607294,"DepthValue":18.44377295716579,"WidthValue":16.732108234801206}];
// your numeric keys
var numKeys = ['ShareValue','ReachValue','DepthValue','WidthValue'];
var res = j.map(e => Object.assign(e, // rewrite each object
...Object.keys(e).filter(k => numKeys.indexOf(k) > -1) // pick keys which include 'Value'
.map(v => Object.assign({[v]: parseFloat(e[v]).toFixed(2)})) // chop numbers
))
console.log(res)
Related
I have an array that looks like this:
var myArray = [ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ]
When the user enters name1, I would like to open an alert box and display data1, for name2 it should display data2, and so on.
In order to do this, I was wondering how I could split all the strings without using more than one array? And how do I display only data1 when name1 is entered by the user?
I’ve tried using myArray.split("+") but it does not work.
You could map the splitted strings and get an object form the key/value pairs.
var array = ['name1+data1', 'name2+data2', 'name3+data3', 'name4+data4'],
object = Object.fromEntries(array.map(s => s.split('+')));
console.log(object);
You could try implementing below function that takes two arguments.
targetArray is the array to perform search and searchString is the string to search. In your case searchString would be name1. The time complexity is based on the position of the element in the array O(K).
function findMatch(targetArray, searchString) {
const targetElement = targetArray.find(item => {
const leftSplit = item.split('+')[0];
return leftSplit === searchString;
});
if (targetElement) {
return targetElement.split('+')[1];
} else {
return null;
}
}
window.alert(
findMatch([ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ], 'name2')
);
Alerts: "data2"
If it is an array, then you need to iterate through the array.
const output = myArray.filter(arrayItem => arrayItem.includes(userInput))[0].split('+')[0];
The time complexity here would be O(N+M), where N is length of array and M is the length of the string.
I think it would be better if myArray is maintained as a dictionary,
const myArray = {
name1: 'data1',
name2: 'data2',
name3: 'data3'
}
const output = myArray[userInput];
The time complexity would be decreased to O(1)
You could use this snippet
var myArray = [ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ];
var userValue = prompt('Valeur à rechercher...');
myArray.map((item) => {
if(~item.search(userValue) && userValue.length > 0){
alert(item.split('+')[1]);
return false;
}
})
So, here's an example where name1 and name2 have values, but not the others:
let pairs = [ "name1+data1" , "name2+data2" , "name3+", "name4+" ]
We can split each of those into two-element arrays:
let arr = pairs.map(p=>p.split('+'))
And filter out the ones with empty names:
arr = arr.filter(a=>a[1].length > 0)
arr.join("\n") // "name1,data1
// name2,data2"
Does that do what you want?
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.
Probably a dumb question, Assume i have an object like below,
{"Country":"country","Continent":"continent","Province":"","District":"","State":"state","City":""}"
What is the quickest way to check which properties hold the values in the above object without using a loop?
while doing this inside a for loop is working,
if(typeof someUndefVar == whatever) -- works
EXPECTED OUTPUT:
Country, Continent and State
var a = {"Country":"country","Continent":"continent","Province":"","District":"","State":"state","City":""};
Object.keys(a).filter( prop => a[prop] );
It also depends on how you want to handle the 0, null, undefined values.
You might do as follows;
var obj = {"Country":"country","Continent":"continent","Province":"","District":"","State":"state","City":""};
for (var prop in obj) !!obj[prop] && console.log(prop);
You need to use the object.keys() function,
Like this,
var jsonData= {"Country":"country","Continent":"continent","Province":"","District":"","State":"state","City":""};
console.log(Object.keys(jsonData));
Hope this helps!
Sorry you said no loop and I got excited and I was bored and I got functional.
First I shortened some names and I guess they are kind of self explanatory:
head: first element of an array
tail: all the elements but the first
isEmpty: check if an array has length 0
transform does the actual work using a callback, it stops if the keys array is empty if not goes recursive.
var data = {"Country":"country","Continent":"continent","Province":"","District":"","State":"state","City":""}
// plumbing
var head = (a) => a[0]
var tail = (a) => a.slice(1)
var isEmpty = (a) => a.length === 0
// actual stuff happens here
var transform = (obj, callback) => {
var withval = (keys) => {
if(isEmpty(keys)) return
var p = head(keys)
if(!!obj[p]) callback(p)
withval(tail(keys))
}
withval(Object.keys(obj))
}
// Logs
var log = (p) => console.log(p)
transform(data, log)
// Array making
var arr = [];
var toArr = (p) => arr.push(p)
transform(data, toArr)
console.log(arr)
// Object making
var obj = {}
var toObj = (p) => obj[p] = data[p]
transform(data, toObj)
console.log(obj)
Outcome:
Country
Continent
State
[ 'Country', 'Continent', 'State' ]
{ Country: 'country', Continent: 'continent', State: 'state' }
i have a arrray of objects where i wish to convert the data from medicine to type string. The only problem is instead of returning the array of objects is returing me the array of medicine.
Example
input:
data = [{medicine: 1234, info: "blabla"},{medicine: 9585, info: "blabla"},..]
desired output:
data = [{medicine: "1234", info: "blabla"},{medicine: "9585", info: "blabla"},..]
What im getting?
Array of medicine numbers.
Here is my code:
var dataMedicines = _.map(data, 'medicine').map(function(x) {
return typeof x == 'number' ? String(x) : x;
});
Lodash is much powerful, but for simplicity, check this demo
var data = [{
medicine: 1234,
info: "blabla"
}, {
medicine: 9585,
info: "blabla"
}];
dataMedicines = _.map(data, function(x) {
return _.assign(x, {
medicine: x.medicine.toString()
});
});
console.log(dataMedicines);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
Or just a native ES6 solution:
const dataMedicines = data.map(({medicine, info}) => ({medicine: `${medicine}`, info}));
The advantage is that this is a more functional solution that leaves the original data intact.
I'm guessing you want "transform" all medicine number to strings?
If that's the case, you don't need to first map.
var dataMedicines = _.map(data, function(x){
var newObj = JSON.parse(JSON.stringify(x)); // Create a copy so you don't mutate the original.
newObj.medicine = newObj.medicine.toString(); // Convert medicine to string.
return newObj;
});
I'm looking to get an array from a variable. If it's not already an array I want to return a new array with the variable as the only entry.Example:
toArray('test'); // => ["test"]
toArray(['test']); // => ["test"]
My actual working code is:
var toArray;
toArray = function(o) {
if (Array.isArray(o)) {
return o.slice();
} else {
return [o];
}
};
I'd like to know if there is a nicer way for that (native or with underscore.js for example).
In ruby, you can do:
Array('test') # => ["test"]
Array(['test']) # => ["test"]
Just use .concat().
[].concat("test"); // ["test"]
[].concat(["test"]); // ["test"]
Arrays will be flattened into the new Array. Anything else will simply be added.
function toArray(o) {
return Array.isArray(o) ? o.slice() : [o];
};
I believe you can slice it:
var fooObj = {0: 123, 1: 'bar', length: 2};
var fooArr = Array.prototype.slice.call(fooObj);
Demo: http://jsfiddle.net/sh5R9/