Related
I need help in transforming data in a particular way to plot a graph. The data which I get from API is a different format. Please guide me on how to transform it
const demo = [
{
label: 'ABC',
vMini: 28,
vMaxi: 56,
dMini: 2,
dMaxi: 50,
},
{
label: 'BCD',
vMini: 2,
vMaxi: 56,
dMini: 3,
dMaxi: 50,
},
];
end result which i want is
[
{
section: "vMini",
"ABC": 28,
"BCD": 2,
},
{
section: "vMaxi",
"ABC": 56,
"BCD": 56
}
{
section: "dMini",
"ABC": 2,
"BCD": 3,
},
{
section: "dMaxi",
"ABC": 50,
"BCD": 50
}
]
I have started working on it and got confused with second loop.
for (let i = 0; i < demo.length; i += 1) {
for (let j in demo[i]) {
if (j === 'label') {
}
}
}
This one is a bit tricky with the way the data is structured, but you should be able to do this with array.reduce, like so:
const demo = [{label:"ABC",vMini:28,vMaxi:56,dMini:2,dMaxi:50},{label:"BCD",vMini:2,vMaxi:56,dMini:3,dMaxi:50}];
// get array of keys, and create a new object for each one except label
// ["label", "vMini", "vMaxi", "dMini", "dMaxi"]
let results = Object.keys(demo[0]).reduce((res, key) => {
if (key === "label") { return res; }
else {
// for each item in demo, create a key for the label and grab the key's value
let newObj = demo.reduce((_res, obj) => {
_res[obj.label] = obj[key];
return _res;
}, {section: key})
// push the new object into the results array
res.push(newObj);
}
return res;
}, [])
console.log(results);
Using reduce() and Map()
const demo = [{label:"ABC",vMini:28,vMaxi:56,dMini:2,dMaxi:50},{label:"BCD",vMini:2,vMaxi:56,dMini:3,dMaxi:50}];
const resMap = demo.reduce((a, v) => {
let label = v.label
for (let k in v) {
if (k == 'label') continue
a.has(k) || a.set(k, { section: k })
let o = a.get(k)
o[label] = v[k]
}
return a
}, new Map())
const resArr = [...resMap.values()]
console.log(resArr)
let say i have 1 multidimensional array and i want to exclude values that not equal in javascript.
here is the example array.
var filter = ["big_number", "odds_number"];
var arrays = {
"first" : {
"big_number" : [50,51,52],
"odds_number" : [39,41,51,53]
},
"second" : {
"big_number" : [61,62,63,64,65,70,72,73],
"odds_number" : [13,15,17,19,61,63,65,73]
}
};
i want to convert that array to be like this.
var new_arrays = {
"first" : [51],
"second" : [61,63,65,73]
};
here is my code
var newArray = {
"first" : [],
"second" : []
};
for (var k in arrays){
if (arrays.hasOwnProperty(k)) {
for(var f=0; f<filter.length; f++) {
newArray[k].push(arrays[k][filter[f]].filter(value => -1 !== arrays[k][filter[f]].indexOf(value))));
}
}
}
console.log(newArray);
actually i could do this code
var newArray = {
"first" : [],
"second" : []
};
for (var k in arrays){
if (arrays.hasOwnProperty(k)) {
newArray[k].push(arrays[k]["big_number"].filter(value => -1 !== arrays[k]["odds_number"].indexOf(value))));
}
}
console.log(newArray);
but i need to convert it through filter variable.
i could not use filter[0] and filter[1], because that values could change dynamically and could be more than 2 values in array.
You could loop through the keys and update the values using filter and includes:
var arrays={"first":{"big_number":[50,51,52],"odds_number":[39,41,51,53]},"second":{"big_number":[61,62,63,64,65,70,72,73],"odds_number":[13,15,17,19,61,63,65,73]}};
for (let key in arrays) {
arrays[key] = arrays[key]["big_number"]
.filter(n => arrays[key]["odds_number"].includes(n));
}
console.log(arrays)
If you don't want to mutate the original object then use Object.entries and reduce:
var arrays={"first":{"big_number":[50,51,52],"odds_number":[39,41,51,53]},"second":{"big_number":[61,62,63,64,65,70,72,73],"odds_number":[13,15,17,19,61,63,65,73]}};
const newObject = Object.entries(arrays).reduce((r, [key, {big_number, odds_number}]) => {
r[key] = big_number.filter(n => odds_number.includes(n));
return r
}, {})
console.log(newObject)
If you have more than 2 array properties, you can do something like this: Get all the arrays using Object.values and then use reduce to run the previous code recursively
var arrays = {
"first": {
"big_number": [50, 51, 52],
"odds_number": [39, 41, 51, 53],
"another_key": [41, 51, 53]
},
"second": {
"big_number": [61, 62, 63, 64, 65, 70, 72, 73],
"odds_number": [13, 15, 17, 19, 61, 63, 65, 73],
"another_key": [63, 65]
}
};
for (let key in arrays) {
arrays[key] = Object.values(arrays[key])
.reduce((a, b) => a.filter(c => b.includes(c)))
}
console.log(arrays)
Here is a little intersection snippet:
function intersect(a,b){
b.slice()
return a.filter(item=>{
if(b.includes(item)){
b.splice(b.indexOf(item),1)
return true
}
})
}
Using that, you can do this easily:
function intersect(a,b){
b.slice()
return a.filter(item=>{
if(b.includes(item)){
b.splice(b.indexOf(item),1)
return true
}
})
}
var filter = ["big_number", "odds_number"];
var output={}
var arrays = {
"first" : {
"big_number" : [50,51,52],
"odds_number" : [39,41,51,53]
},
"second" : {
"big_number" : [61,62,63,64,65,70,72,73],
"odds_number" : [13,15,17,19,61,63,65,73]
}
};
for(x in arrays){
output[x]=arrays[x][filter[0]]
for(let i=1;i<filter.length;i++){
output[x]=intersect(output[x],arrays[x][filter[i]])
}
}
console.log (output)
use Object.entries to get keys and values and then use reduce
var arrays = {
"first" : {
"big_number" : [50,51,52],
"odds_number" : [39,41,51,53]
},
"second" : {
"big_number" : [61,62,63,64,65,70,72,73],
"odds_number" : [13,15,17,19,61,63,65,73]
}
};
const output =Object.entries(arrays).reduce((accu, [key, {big_number}]) => {
if(!accu[key]) accu[key] = [];
big_number.forEach(num => {
if(num%2 !==0)
accu[key].push(num);
})
return accu;
}, {});
console.log(output);
You can get the unique values from both the arrays using Set and then using filter get only the common values.
var arrays = {"first": {"big_number": [50, 51, 52],"odds_number": [39, 41, 51, 53]},"second": {"big_number": [61, 62, 63, 64, 65, 70, 72, 73],"odds_number": [13, 15, 17, 19, 61, 63, 65, 73]}},
result = Object.keys(arrays).reduce((r,k) => {
let setB = new Set(arrays[k]["big_number"]);
r[k] = [...new Set(arrays[k]["odds_number"])].filter(x => setB.has(x));
return r;
},{});
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
I need to transmit some data, that has too many key-value pairs.
As the keys are similar, I dont want to transmit them with each object.
Consider I have the following data:
[
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
];
And I need the final output as
[ [x,y],[[11,12],[21,22],[31,32],[41,42]] ] OR
[ [x,y],[11,12],[21,22],[31,32],[41,42] ]
On the other end, I should be able to convert back to its original form.
It would be great if it can handle an additional key in some of the objects
I think I have seen lodash or underscore function for something close/similar to this, but I'm not able to find it right now.
NOTE: I don't know what the keys will be
Lodash v4.17.1
modify original
var modifiedOriginal = _.chain(original)
.map(_.keys)
.flatten()
.uniq()
.thru(function(header){
return _.concat(
[header],
_.map(original, function(item) {
return _.chain(item)
.defaults(_.zipObject(
header,
_.times(_.size(header), _.constant(undefined))
))
.pick(header)
.values()
.value()
})
);
})
.value();
modified back to original (keys order is not
guarantee)
var backToOriginal = _.map(_.tail(modified), function(item) {
return _.chain(_.head(modified))
.zipObject(item)
.transform(function(result, val, key) {
if (!_.isUndefined(val)) {
result[key] = val;
}
})
.value();
});
JSFiddle code https://jsfiddle.net/wa8kaL5g/1/
Using Array#reduce
var arr = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
var keys = Object.keys(arr[0]);
var op = arr.reduce(function(a, b) {
var arr = keys.reduce(function(x, y) {
return x.concat([b[y]]);
}, [])
return a.concat([arr]);
}, [keys]); //If all the objects are having identical keys!
console.log(JSON.stringify(op));
A little more verbose way of doing it:
[Edit: added the function to convert it back]
function convert(arr) {
var retArr = [ [/* keys (retArr[0]) */], [/* values (retArr[1]) */] ]
arr.forEach(function(obj){
// create new array for new sets of values
retArr[1].push([])
// put all of the keys in the correct array
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// does the key exist in the array yet?
if (retArr[0].indexOf(key) === -1) {
retArr[0].push(key)
}
// get last index of retArr[1] and push on the values
retArr[1][retArr[1].length - 1].push(obj[key])
}
}
})
return retArr
}
function reConvert(arr) {
var retArr = []
var keys = arr[0]
arr[1].forEach(function(itemArr){
var obj = {}
itemArr.forEach(function(item, i){
obj[keys[i]] = item
})
retArr.push(obj)
})
return retArr
}
var objArr = [
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
]
var arrFromObj = convert(objArr)
var objFromArr = reConvert(arrFromObj)
console.log(arrFromObj)
console.log(objFromArr)
A solution using Underscore.
First work out what the keys are:
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
Then map across the data to pick out the value for each key:
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
and back again:
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
Lodash's version of object is zipObject and omit using a predicate is omitBy:
var thereAndBackAgain = _.map(result[1], item => _.omitBy(_.zipObject(result[0], item), _.isUndefined));
var data = [
{
x:11,
y:12,
aa: 9
},{
x:21,
y:22
},{
x:31,
y:32,
z: 0
},{
x:41,
y:42
}
];
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
console.log(result)
console.log(thereAndBackAgain)
<script src="
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In ES6 you can do it by reducing it with Object.values(), and Object.keys(). You can restore it using a combination of Array.prototype.map() and Array.prototype.reduce():
const convertStructure = (data) => data.reduce((s, item) => {
s[1].push(Object.values(item));
return s;
}, [Object.keys(data[0]), []]); // all objects should be the same, so we can take the keys from the 1st object
const restoreStructure = ([keys, data]) => data.map((item) => item.reduce((o, v, i) => {
o[keys[i]] = v;
return o;
}, {}));
const data = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
const convertedStructure = convertStructure(data);
console.log('convertedStructure:\n', convertedStructure);
const restoredStructure = restoreStructure(convertedStructure);
console.log('restoredStructure:\n', restoredStructure);
I have an array with a list of objects:
var myArray = [
{"cartItems": {"paramA1": 25, "paramA2": 35}},
{"cartShippingCost": {"paramB1": 4, "paramB2": 152, "paramB3": 536, "paramB4": 56}},
{"cartSpecialRequirements": {"paramC1": 432}},
{"cartPostage": {"paramD1": 56, "paramD2": 6537}},
{"uid": {"paramE1": 545}},
{"tel": 7778798548}
];
How can i loop through the above and group objects that contain 'cart' and ones that don't?
I know i need to create 2 temp obj's e.g.
var cartObj;
var nonCartObj;
And perform a .push in to each of these if the condition is met.
Tried:
for(var i in myArray) {
if (i == 'cart') {
console.log('cart match found');
}
}
Update:
Using Object.keys always hitting else case:
var key = Object.keys(item);
if (key.indexOf("cart") !== -1) {
alert(key + " contains cart");
} else {
alert(key + " doesnt contain cart");
}
You can use Array.prototype.filter to create a new array where each item satisfies some condition:
var cartItems = myArray.filter(hasCartProperty);
var nonCartItems = myArray.filter(function (x) { return !hasCartProperty(x); });
// Checks to see if any of the object's keys contain the text 'cart'
function hasCartProperty(x) {
return Object.keys(x).some(function (x) {
return x.indexOf('cart') > -1;
});
}
Loop through each item of the array, and then inside that loop iterate over the object keys to find what you're looking for
var result = [];
myArray.forEach(function (item) {
for (var key in item) {
if (key.indexOf('cart') !== -1) {
result.push(item);
}
}
});
console.log(result);
The JavaScript Array object has a filter function that can be used for this.
The tricky part is the function that performs the filtering. One way to do that is to iterate the keys in the objects to detect which ones contain "cart" keys.
var myArray = [
{"cartItems": {"paramA1": 25, "paramA2": 35}},
{"cartShippingCost": {"paramB1": 4, "paramB2": 152, "paramB3": 536, "paramB4": 56}},
{"cartSpecialRequirements": {"paramC1": 432}},
{"cartPostage": {"paramD1": 56, "paramD2": 6537}},
{"uid": {"paramE1": 545}},
{"tel": 7778798548}
];
var cartObj = myArray.filter(function (x) { return isCart(x); });
var nonCartObj = myArray.filter(function (x) { return !isCart(x); });
console.log("cart count = " + cartObj.length + ", non-cart count = " + nonCartObj.length);
function isCart(x) {
for (var key in x) {
if (x.hasOwnProperty(key) && key.startsWith("cart")) {
return true;
}
}
return false;
}
A solution with one loop without Array#filter().
var myArray = [{ "cartItems": { "paramA1": 25, "paramA2": 35 } }, { "cartShippingCost": { "paramB1": 4, "paramB2": 152, "paramB3": 536, "paramB4": 56 } }, { "cartSpecialRequirements": { "paramC1": 432 } }, { "cartPostage": { "paramD1": 56, "paramD2": 6537 } }, { "uid": { "paramE1": 545 } }, { "tel": 7778798548 }],
grouped = function (array) {
var r = { cart: [], nonCart: [] };
array.forEach(function (a) {
Object.keys(a).some(function (k) {
if (k.indexOf('cart') === 0) {
return r.cart.push(a);
}
}) || r.nonCart.push(a);
});
return r;
}(myArray);
document.write('<pre>' + JSON.stringify(grouped, 0, 4) + '</pre>');
var addObjectResponse = [{
'DateTimeTaken': '/Date(1301494335000-0400)/',
'Weight': 100909.090909091,
'Height': 182.88,
'SPO2': '222.00000',
'BloodPressureSystolic': 120,
'BloodPressureDiastolic': 80,
'BloodPressurePosition': 'Standing',
'VitalSite': 'Popliteal',
'Laterality': 'Right',
'CuffSize': 'XL',
'HeartRate': 111,
'HeartRateRegularity': 'Regular',
'Resprate': 111,
'Temperature': 36.6666666666667,
'TemperatureMethod': 'Oral',
'HeadCircumference': '',
}];
This is a sample object which i am getting from back end, now i want to change the order of the object. I don't want to sort by name or size... i just want to manually change the order...
If you create a new object from the first object (as the current accepted answer suggests) you will always need to know all of the properties in your object (a maintenance nightmare).
Use Object.assign() instead.
*This works in modern browsers -- not in IE or Edge <12.
const addObjectResponse = {
'DateTimeTaken': '/Date(1301494335000-0400)/',
'Weight': 100909.090909091,
'Height': 182.88,
'SPO2': '222.00000',
'BloodPressureSystolic': 120,
'BloodPressureDiastolic': 80,
'BloodPressurePosition': 'Standing',
'VitalSite': 'Popliteal',
'Laterality': 'Right',
'CuffSize': 'XL',
'HeartRate': 111, // <-----
'HeartRateRegularity': 'Regular', // <-----
'Resprate': 111,
'Temperature': 36.6666666666667,
'TemperatureMethod': 'Oral',
'HeadCircumference': '',
};
// Create an object which will serve as the order template
const objectOrder = {
'HeartRate': null,
'HeartRateRegularity': null,
}
const addObjectResource = Object.assign(objectOrder, addObjectResponse);
The two items you wanted to be ordered are in order, and the remaining properties are below them.
Now your object will look like this:
{
'HeartRate': 111, // <-----
'HeartRateRegularity': 'Regular', // <-----
'DateTimeTaken': '/Date(1301494335000-0400)/',
'Weight': 100909.090909091,
'Height': 182.88,
'SPO2': '222.00000',
'BloodPressureSystolic': 120,
'BloodPressureDiastolic': 80,
'BloodPressurePosition': 'Standing',
'VitalSite': 'Popliteal',
'Laterality': 'Right',
'CuffSize': 'XL',
'Resprate': 111,
'Temperature': 36.6666666666667,
'TemperatureMethod': 'Oral',
'HeadCircumference': '',
}
I wrote this small algorithm which allows to move keys, it's like jQuery .insertAfter() method. You have to provide:
//currentKey: the key you want to move
//afterKey: position to move-after the currentKey, null or '' if it must be in position [0]
//obj: object
function moveObjectElement(currentKey, afterKey, obj) {
var result = {};
var val = obj[currentKey];
delete obj[currentKey];
var next = -1;
var i = 0;
if(typeof afterKey == 'undefined' || afterKey == null) afterKey = '';
$.each(obj, function(k, v) {
if((afterKey == '' && i == 0) || next == 1) {
result[currentKey] = val;
next = 0;
}
if(k == afterKey) { next = 1; }
result[k] = v;
++i;
});
if(next == 1) {
result[currentKey] = val;
}
if(next !== -1) return result; else return obj;
}
Example:
var el = {a: 1, b: 3, c:8, d:2 }
el = moveObjectElement('d', '', el); // {d,a,b,c}
el = moveObjectElement('b', 'd', el); // {d,b,a,c}
You can't order JavaScript object key/value pairs. It's stored in its own internal format, so you should never rely on the order of that. In JS, everything is an Object, even an Array. So sometimes you can introduce bugs when using array notation and object notation together (for x in var)
I like the approved answer by Chamika Sandamal. Here's a simple function that uses their same logic with a little be of freedom to change the order as you need it.
function preferredOrder(obj, order) {
var newObject = {};
for(var i = 0; i < order.length; i++) {
if(obj.hasOwnProperty(order[i])) {
newObject[order[i]] = obj[order[i]];
}
}
return newObject;
}
You give it an object, and an array of the key names you want, and returns a new object of those properties arranged in that order.
var data = {
c: 50,
a: 25,
d: 10,
b: 30
};
data = preferredOrder(data, [
"a",
"b",
"c",
"d"
]);
console.log(data);
/*
data = {
a: 25,
b: 30,
c: 50,
d: 10
}
*/
I'm copying and pasting from a big JSON object into a CMS and a little bit of re-organizing of the source JSON into the same order as the fields in the CMS has saved my sanity.
2020 Update
The answer below was correct at time of writing in 2011. However, since ES6, enumeration order has been specified as part of the language. Here's a nice article summarising this: https://2ality.com/2015/10/property-traversal-order-es6.html
Original answer
Properties of an object in JavaScript do not have an order. There may appear to be an order in some browsers but the ECMAScript specification defines object property enumeration order as being implementation-specific so you should not assume one browser's behaviour will be the same as another's. Chrome, for example, does not use the same ordering as some other browsers: see this lengthy bug report for at least as much discussion of this issue as you could possibly want.
If you need a specific order, use an array, or two arrays (one for keys and one for values).
You can use Object.keys():
var obj = {
a: 1,
b: 2,
c: 4
};
var new_obj = {};
Object.keys(obj)
.sort(function(a, b) {
/** Insert your custom sorting function here */
return a - b;
})
.forEach(function(key) {
new_obj[key] = obj[key];
});
obj = new_obj;
if you want to manually reorder. simply create new object and assign values using old object.
var newObject= [{
'DateTimeTaken': addObjectResponse.DateTimeTaken,
'Weight': addObjectResponse.Weight,
'Height': addObjectResponse.Height,
'SPO2': addObjectResponse.SPO2
}];
If you do not want to create a new object, you can use the following code snippet.
function orderKey(obj, keyOrder) {
keyOrder.forEach((k) => {
const v = obj[k]
delete obj[k]
obj[k] = v
})
}
here is a codepen: https://codepen.io/zhangyanwei/pen/QJeRxB
I think that's not possible in JavaScript.
You can create an array which will contain the field names in your order and you can iterate through this array and fetch the fields from the actual object.
Just refer to the object keys in the order that you like:
aKeys = [
addObjectResponse[0].DateTimeTaken,
addObjectResponse[0].Weight,
addObjectResponse[0].Height,
...etc...
]
I wrote a quick function in TypeScript that takes 2 arguments. The first is the array of objects you want to change the keys of, the second is an array of strings that represent the order of keys you'd like returned.
type GenericObject = Record<string, any> | null;
const order:Function = (data: Array<GenericObject>, order: Array<string>): Array<GenericObject> => {
return data.map((node) => {
return order.reduce((runningValue, currentValue) => {
return Object.assign(runningValue, { [currentValue]: node?.[currentValue]});
}, {});
});
};
And here is an example of calling it:
const data: Array<GenericObject> = [
{ b: 1, a: 2},
{ b: 3, a: 4},
];
const orderIWant: Array<string> = ['a', 'b'];
const ordered: Array<GenericObject> = order(data, orderIWant);
console.log(ordered);
// [ { a: 2, b: 1 }, { a: 4, b: 3 } ]
function orderKeys(obj, keys){
const newObj = {};
for(let key of keys){
newObj[key] = obj[key];
}
return newObj;
}