I have a json object and a dummy json response.
I need to loop through it and get a new array of each coordinates, one per loop.
Sample JSON:
customersBarChart: {
"2014": {
"x": 1,
"y": 5,
"z":10
},
"2015": {
"x": 8,
"y": 2,
"z":5
},
}
The expected result is:
first X loop MyArray = [1,8]
second Y loop MyArray = [5,2]
third Z loop MyArray = [10,5]
You can loop over objects using for (let o in obj) and get the values from there. You can now make 3 separate arrays by pushing the data from obj[o] onto the end of the specified array.
let obj = {
"2014": {
"x": 1,
"y": 5,
"z": 10
},
"2015": {
"x": 8,
"y": 2,
"z": 5
},
}
let arr1 = []
let arr2 = []
let arr3 = []
for (let o in obj) {
arr1.push(obj[o].x)
arr2.push(obj[o].y)
arr3.push(obj[o].z)
}
console.log(arr1.join())
console.log(arr2.join())
console.log(arr3.join())
here is how to handle things dynamically.
var oData = {
customersBarChart: {
"2014": {
"x": 1,
"y": 5,
"z": 10
},
"2015": {
"x": 8,
"y": 2,
"z": 5
},
}
}
function extractData(data) {
// get the keys of the customersBarChart object
var keys = Object.getOwnPropertyNames(data);
// get the keys of the object in the first item in customersBarChart object
// and initialize an array
var attrs = Object.getOwnPropertyNames(data[keys[0]]).map(function(k) {
return {
key: k,
arr: []
};
});
// looping thru the attrs to collect the val for the array
attrs.forEach(function(attr) {
keys.forEach(function(k) {
attr.arr.push(data[k][attr.key]);
});
});
// drop the key property in attrs object
return attrs.map(function(attr) {
return attr.arr;
});
}
console.log(extractData(oData.customersBarChart));
Related
I tried to create new array object from array , set rank according to its value . If value is the same, set the same rank and if next value is different set rank by skipping same rank length .
Expected result is
[
{
"rank": 1,
"data": 45
},
{
"rank": 2,
"data": 33
},
{
"rank": 3,
"data": 8
},
{
"rank": 4,
"data": 5
},
{
"rank": 4,
"data": 5
},
{
"rank": 6,
"data": 2
}
]
var data = [8,5,2,33,5,45];
var rankList = [];
var uniqueList = [];
var rank = 0;
var sameRank = 0;
data.sort(function(a,b) { return b - a; });
for(var i in data) {
if(uniqueList.includes(data[i])) {
rank++;
rankList.push({rank: sameRank, data: data[i]});
continue;
}
rank++;
sameRank++;
rankList.push({rank: rank, data: data[i]});
}
console.log(rankList);
Once you've sorted the array, create another array of objects with .map, keeping track of the last rank and data used. If the new data is the same, use the same rank (the one taken from a prior iteration) - otherwise, use the current iteration index plus 1:
const data = [8, 5, 2, 33, 5, 45];
data.sort((a, b) => b - a);
let lastRank = 0;
let lastData;
const output = data.map((data, i) => {
const objToReturn = { data };
objToReturn.rank = data === lastData ? lastRank : i + 1;
lastData = data;
lastRank = objToReturn.rank;
return objToReturn;
});
console.log(output);
I am facing a problem.
var arr = ['VBH', 'KTL', 'PVC', 'IF & AF', 'BC', 'CC&HC', 'UBS', 'FAD&DVD'];
var obj = [
{"materialTypeID":9,"name":"","abbreviation":"UBS","count":1,"duns":0,"plantId":0},
{"materialTypeID":18,"name":null,"abbreviation":"PVC","count":1,"duns":0,"plantId":0},
{"materialTypeID":7,"name":"","abbreviation":"FAD&DVD","count":4,"duns":0,"plantId":0}
];
and I want the result in sorting format as arr variable shows such as VBH object or KTL object if they found.
[
{"materialTypeID":18,"name":null,"abbreviation":"PVC","count":1,"duns":0,"plantId":0},
{"materialTypeID":9,"name":"","abbreviation":"UBS","count":1,"duns":0,"plantId":0},
{"materialTypeID":7,"name":"","abbreviation":"FAD&DVD","count":4,"duns":0,"plantId":0}
]
In java script, I want to implement.
Thanks,
Loop the arr and use filter to get the element from the obj. filter will return a new array, check if the length of this new array is more than 0 , then use push to put the element
var arr = ['VBH', 'KTL', 'PVC', 'IF & AF', 'BC', 'CC&HC', 'UBS', 'FAD&DVD']
var obj = [{
"materialTypeID": 9,
"name": "",
"abbreviation": "UBS",
"count": 1,
"duns": 0,
"plantId": 0
}, {
"materialTypeID": 18,
"name": null,
"abbreviation": "PVC",
"count": 1,
"duns": 0,
"plantId": 0
}, {
"materialTypeID": 7,
"name": "",
"abbreviation": "FAD&DVD",
"count": 4,
"duns": 0,
"plantId": 0
}]
let sortedArray = [];
arr.forEach(function(item) {
let getElem = obj.filter(function(items) {
return items.abbreviation === item
})
if (getElem.length > 0) {
sortedArray.push(getElem[0])
}
})
console.log(sortedArray)
It seems that you want to sort by decreasing materialTypeID.
Your problem has already been resolved there : Javascript object list sorting by object property
obj.sort(function(a, b) {
return b.materialTypeID - a.materialTypeID;
})
I have the following javascript code which produces the desired results, i.e. returns both the 3rd and 4th objects in objectsArray since they both contain the max distance. However, I'm wondering if there is a way to not have to retype the name of the array when calling objectsArray.filter? I'm not trying to be lazy, just avoiding redundancy and the possibility of introducing a typo.
function meetsMax(obj) {
return obj.distance === Math.max.apply(Math, this.map(function(o) { return o.distance; }));
}
const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];
const objMax = objectsArray.filter(meetsMax, objectsArray);
console.log("objMax:", objMax);
I certainly wouldn't mind any other pointers on making the code more efficient and performant.
Function calls in JavaScript have some overhead, so native code is more efficient and performant:
var a = [ { "distance": 1, "name": "first" }, { "distance": 2, "name": "second" },
{ "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" } ]
for (var o = a[0], objMax = [o], m = o.distance, d, i = 1; i < a.length; i++)
if ((d = (o = a[i]).distance) > m) { objMax = [o]; m = d }
else if (d === m) objMax[objMax.length] = o
console.log(JSON.stringify(objMax))
There are also shorter and less efficient alternatives:
var a = [ { "distance": 1, "name": "first" }, { "distance": 2, "name": "second" },
{ "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" } ]
var d, b = []; a.forEach(o => (b[d = o.distance] = b[d] || []).push(o))
console.log(JSON.stringify(b[b.length - 1]))
Why don't you use for loop? It will be faster than your code.
"use strict";
let start = performance.now();
for (let z = 0; z < 1000; z++) {
function meetsMax(obj) {
return obj.distance === Math.max.apply(Math, this.map(function(o) { return o.distance; }));
}
const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];
const objMax = objectsArray.filter(meetsMax, objectsArray);
}
let fin = performance.now() - start;
console.log(fin); // 3.25ms
"use strict";
let start = performance.now();
for (let z = 0; z < 1000; z++) {
let a = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];
let maxDistance = 0;
let result = [];
for (let i = 0, max = a.length; i < max; i++) {
if (a[i].distance > maxDistance) {
maxDistance = a[i].distance;
}
}
for (let i = 0, max = a.length; i < max; i++) {
if (a[i].distance === maxDistance) {
result.push(a[i]);
}
}
}
let fin = performance.now() - start;
console.log(fin); // 1.28ms
.filter passes three arguments to the array: the current value, the index of the current value and the array itself. So you can change your filter function to:
function meetsMax(obj, index, objectsArray) {
return obj.distance === Math.max.apply(Math, objectsArray.map(function(o) { return o.distance; }));
}
and call .filter with
objectsArray.filter(meetsMax);
Always read the documentation of the functions you are using.
I certainly wouldn't mind any other pointers on making the code more efficient and performant.
If you, compute the maximum distance only once instead of in every iteration of the array. E.g. you could do:
function filterMax(arr, extractor) {
const max = arr.reduce(function(max, item) {
return max < extractor(item) ? extractor(item) : max;
}, extractor(arr[0]));
return arr.filter(function(item) {
return extractor(item) === max;
});
}
and call it as
filterMax(objectsArray, function(obj) { return obj.distance; });
function filterMax(arr, extractor) {
const max = arr.reduce(function(max, item) {
return max < extractor(item) ? extractor(item) : max;
}, extractor(arr[0]));
return arr.filter(function(item) {
return extractor(item) === max;
});
}
const objectsArray = [{ "distance": 1, "name": "first" }, { "distance": 2, "name": "second" }, { "distance": 3, "name": "third" }, { "distance": 3, "name": "fourth" }];
console.log(filterMax(objectsArray, function(obj) {
return obj.distance;
}));
According to MDN's Array.prototype.filter(), the array name is an optional override to the internal value of this.
So to answer the original question:
I'm wondering if there is a way to not have to retype the name of the array when calling objectsArray.filter?
Yes, you can safely leave it out.
var filter = function(x) { if (x > 5) return true; };
var arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
alert(arr.filter(filter).join(","));
or even simpler (albeit harder to read):
alert([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].filter(function(x) { if (x > 5) return true; }));
You specifically asked about an object, but you're not filtering objects, you're filtering an array of objects, so same applies.
console.log([ {foo: 1}, {foo: 2}, {foo: 3}, {foo: 4}, {foo: 5}, {foo: 6}, {foo: 7}, {foo: 8}, {foo: 9}, {foo: 10}].filter(function(x) { if (x.foo > 5) return true; }));
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
How can I make this
var foo = [{
"number":[1, 2, 3],
"id": [81, 82, 83]
}];
Into this
var foo = [{
"number": 1,
"id": 81
},{
"number": 2,
"id": 82
},{
"number": 3,
"id": 83
}]
I tried .map() and .filter() but they don't turn out the way I need it. Any suggestions? Thanks
You could create a function for that:
function transform(values) {
const result = [];
values.forEach(value => {
value.id.forEach((id, i) => {
result.push({id, number: value.number[i]});
});
});
return result;
}
While I find this to be an odd question, and I'm still hoping for a response regarding my suspicion this is an XY problem, here is a possible approach you can use for whatever you're trying to do.
Let's assume that foo is a single object which only contains enumerable properties that are all arrays of equal length:
var foo = {
"number": [1, 2, 3],
"id": [81, 82, 83]
}
function spread(obj) {
// get the enumerable keys of your object
var keys = Object.keys(obj)
// initialize an empty array
var array = []
// for each key...
keys.forEach(function (key) {
// for each element in the array of the property...
obj[key].forEach(function (value, index) {
// if the array element does not contain an object
// initialize an empty object in index
var base = index < array.length ? array[index] : (array[index] = {})
// assign the value to the key in the element
base[key] = value
})
})
// return the generated array
return array
}
console.log(spread(foo))
You can map the array's object, and thee number array of each object into a new array, then concat the results to flatten the sub arrays into one array.
var foo = [{
"number":[1, 2, 3],
"id": [81, 82, 83]
}];
var result = [].concat.apply([], foo.map(function(obj) { // map the array into sub arrays and flatten the results with concat
return obj.number.map(function(n, i) { // map the number array
return {
number: n,
id: obj.id[i] // get the id value by using the index
};
})
}));
console.log(result);
You need to create a list of objects based on the number of values within a given key.
So, you need to loop over the main list of objects. Inside that loop, you need to loop over the values for a key (i.e. pick the first). You will not need to use these values directly, they are just to determine how many records will be created in the final array. Lastly, you just iterate over the keys again and map the key-values pairs based on the current index.
The Array.prototype.concat.apply([], ...arrays) that happens at the end will combine all the arrays.
The function supports a single object or a list of objects.
var foo = [{
"number" : [ 1, 2, 3],
"id" : [81, 82, 83]
}, {
"number" : [ 4, 5, 6],
"id" : [84, 85, 86]
}];
console.log(JSON.stringify(mapValues(foo), null, 4));
function mapValues(arr) {
arr = !Array.isArray(arr) ? [arr] : arr;
return Array.prototype.concat.apply([], arr.map(item => {
return item[Object.keys(item)[0]].map((val, index) => {
return Object.keys(item).reduce((obj, key) => {
obj[key] = item[key][index];
return obj;
}, {});
});
}));
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Here is another version that does not introduce much complexity.
var foo = [{
"number" : [1, 2, 3],
"id" : [81, 82, 83]
}, {
"number" : [4, 5, 6],
"id" : [84, 85, 86]
}];
console.log(JSON.stringify(mapValues(foo), null, 4));
function mapValues(arr) {
arr = !Array.isArray(arr) ? [arr] : arr;
let records = [], fields;
arr.forEach(item => {
fields = fields || Object.keys(item);
item[fields[0]].forEach((val, index) => {
records.push(fields.reduce((obj, key) => {
obj[key] = item[key][index];
return obj;
}, {}));
});
});
return records;
}
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}
Result
[{
"number": 1,
"id": 81
}, {
"number": 2,
"id": 82
}, {
"number": 3,
"id": 83
}, {
"number": 4,
"id": 84
}, {
"number": 5,
"id": 85
}, {
"number": 6,
"id": 86
}]
I have a scenario wherein i have
var data = [
{
"x": 1,
"y": 0.27,
"classifier": 1
},
{
"x": 2,
"y": 0.88,
"classifier": 1
}
]
I want another object data2 with y=1-y, which i obtain with:
var data2 = data.map(function(el) {el.y = 1-el.y; return el});
data2[0]
Object {x: 1, y: 0.73, classifier: 1}
data2[1]
Object {x: 2, y: 0.12, classifier: 1}
which is the correct form that i want the data in. However the issue is i want to preserve the original data as well. Right now even data has mutated data.
data[0]
Object {x: 1, y: 0.73, classifier: 1}
data[1]
Object {x: 2, y: 0.12, classifier: 1}
Is map the right function to use here? Am i using it correctly?
While creating a new array, you let its values point to the original objects, which you mutate by assigning to their object properties.
Instead you could also create (shallow) copies of the objects with Object.assign:
var data2 = data.map(function(el) {
return Object.assign({}, el, { y: 1-el.y });
});
Or with arrow function:
var data2 = data.map( el => Object.assign({}, el, { y: 1-el.y }) );
var data = [
{
"x": 1,
"y": 0.27,
"classifier": 1
},
{
"x": 2,
"y": 0.88,
"classifier": 1
}
]
var data2 = data.map( el => Object.assign({}, el, { y: 1-el.y }) );
console.log (data);
You're modifying the original element object, which isn't a full deep copy of the original data.
Create a copy of el in the function and then calculate the new .y. For example:
var data2 = data.map(function(el) {
return {
x : el.x,
y : 1-el.y,
classifier : el.classifier
};
});