Loop through multiple objects and get similar key values in new object - javascript

Hi I have array of objects and I am trying to loop through them and have similar key values in new object here is example of data that I have.
let newDats = [{"ID":1, "Name": "Ahmed", "Age":17, "Score":84, "Absentee":3},
{"ID":2, "Name": "Hassan", "Age":15, "Score":87, "Absentee":2},
{"ID":3, "Name": "Aisha", "Age":18, "Score":86, "Absentee":2}]
And so on. However, what I want is something as:
data = [{ID:[1,2,3], Names:["Ahmed", "Hassan","Aisha"],
Ages:[17,15,18]}]
And so forth. My end goal is to perform basic descriptive statistics on the numeric parts of the data so if there is better ideas I would love to hear I am knida newbie to js .
PS
Column names (object keys ) can be more than this and unknown so I want something dynamic.
Thanks in advance.

You can use the function below. Just pass the array you want to sort.
function dataSorter(dataArr) {
const data = {};
for (const item in dataArr[0]) data[item] = [];
for (let i = 0; i < dataArr.length; i++) {
for (const item in dataArr[i]) {
data[item].push(dataArr[i][item]);
}
}
return data;
}
/* Example Below */
let newDats = [{
ID: 1,
Name: "Ahmed",
Age: 17,
Score: 84,
Absentee: 3
},
{
ID: 2,
Name: "Hassan",
Age: 15,
Score: 87,
Absentee: 2
},
{
ID: 3,
Name: "Aisha",
Age: 18,
Score: 86,
Absentee: 2
},
];
console.log(dataSorter(newDats));
.as-console-wrapper { max-height: 100% !important; top: 0; } /* Ignore this */

Something like:
let newDats = [{"ID":1, "Name": "Ahmed", "Age":17, "Score":84, "Absentee":3},
{"ID":2, "Name": "Hassan", "Age":15, "Score":87, "Absentee":2},
{"ID":3, "Name": "Aisha", "Age":18, "Score":86, "Absentee":2}];
data = {};
keys = [];
for(let keyVal in newDats[0]) {
keys.push(keyVal)
data[keyVal] = [];
}
newDats.forEach(dt => {
keys.forEach( kv => {
data[kv].push(dt[kv])
})
})
console.log(data)

You can simply reduce() the array of objects, iterating over all Object.keys() of each element and pushing them to the property array of the accumulator. This allows for each object having different keys.
let newDats = [{ "ID": 1, "Name": "Ahmed", "Age": 17, "Score": 84, "Absentee": 3 }, { "ID": 2, "Name": "Hassan", "Age": 15, "Score": 87, "Absentee": 2 }, { "ID": 3, "Name": "Aisha", "Age": 18, "Score": 86, "Absentee": 2 }];
const result = newDats.reduce((acc, o) => (
Object.keys(o).forEach(k => (acc[k] ??= []).push(o[k])), acc), {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Note the use of the logical nullish assignment operator (??=) which can be replaced by a logical OR short circuit for compatibility.
//acc[k] ??= []
acc[k] = acc[k] || []

Related

Merging items of array of object if they have equal keys

Array of objects that I got
[
{
"id": 1,
"price": 100
},
{
"id": 1,
"price": 80
},
{
"id": 2,
"price": 8
},
{
"id": 1,
"price": 85
}
]
Array of objects that I am trying to do
[
{
"id": 1,
"price": 88.33 // AVERAGE VALUE BETWEEN DUPLICATED OBJECTS
},
{
"id": 2,
"price": 8
}
]
I am merging and getting the average price for duplicated objects.
What I have done:
I have tried to use filter() function but I removed the duplicated without merging the prices.
If you want to avoid extra loops and extra properties is not a problem, you can use a getter for each object as follow:
You can use the function Array.prototype.reduce for grouping objects by id and the function Object.values for extracting the grouped values.
The getter price calculates the average when this property is accessed.
Extra properties:
{
count: Integer // count of repeated ids.
sum: Double // total sum of prices
}
const arr = [ { "id": 1, "price": 100 }, { "id": 1, "price": 80 }, { "id": 2, "price": 8 }, { "id": 1, "price": 85 } ],
result = Object.values(arr.reduce((r, {id, price}) => {
let current = (r[id] || (r[id] = {id, sum: 0, count: 0, get price() {
return this.sum / this.count;
}}));
current.sum += price;
current.count++;
return r;
}, {}));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use .reduce() with an ES6 Map. By using reduce() you can accumulate all objects into a Map, where the key is the id from the object and the value is an accumulated array of price values for the given id. You can then convert the Map back into an array using Array.from(), where you can provide a mapping function to convert the [key, value] pairs from the map into an object. The object's price key will be the sum of all numbers in the value array (arr) divided by the length of the array, which will give you the average.
See example below:
const arr = [ { "id": 1, "price": 100 }, { "id": 1, "price": 80 }, { "id": 2, "price": 8 }, { "id": 1, "price": 85 } ];
const res = Array.from(arr.reduce((m, {id, price}) => {
return m.set(id, [...(m.get(id) || []), price]);
}, new Map), ([id, arr]) => ({id, price: arr.reduce((t, n) => t+n, 0) / arr.length}));
console.log(res);
Use forEach loop and build an object with keys as id and aggregate price.
Use Object.values of above object and calculate the averages.
const data = [
{
id: 1,
price: 100,
},
{
id: 1,
price: 80,
},
{
id: 2,
price: 8,
},
{
id: 1,
price: 85,
},
];
const process = (arr) => {
const res = {};
arr.forEach(({ id, price }) => {
res[id] ??= { id, sum: 0, count: 0 };
res[id].sum += price;
res[id].count += 1;
});
return Object.values(res).map(({ id, sum, count }) => ({
id,
price: sum / count,
}));
};
console.log(process(data));

iterate an array of object and separe comparing dates in es6

I need to make a function to iterate an array of x objects then compare the date inside the objects and separate in different arrays so I can show separately in the HTML, this is my object:
[{"id":1,"date":"2020-02-06","value":131},{"id":2,"date":"2020-02-06","value":135},{"id":3,"date":"2020-02-06","value":141},{"id":4,"date":"2020-02-05","value":151},{"id":6,"date":"2020-02-05","value":155}]
I want something like this:
obj1 = [{"id":1,"date":"2020-02-06","value":131},{"id":2,"date":"2020-02-06","value":135},{"id":3,"date":"2020-02-06","value":141}]
obj2 = [{"id":4,"date":"2020-02-05","value":151},{"id":6,"date":"2020-02-05","value":155}]
my code:
// global variables
json = [{
"id": 1,
"date": "2020-02-06",
"value": 131
}, {
"id": 2,
"date": "2020-02-06",
"value": 135
}, {
"id": 3,
"date": "2020-02-06",
"value": 141
}, {
"id": 4,
"date": "2020-02-05",
"value": 151
}, {
"id": 6,
"date": "2020-02-05",
"value": 155
}];
obj1 = [];
obj2 = [];
for (const x of json) {
if (x.date != x.date) {
obj1.push(x)
} else {
obj2.push(x)
}
}
console.log(obj1);
console.log(obj2);
in result always the items push into the obj1..
any help is welcome.
The typical solution for this is to group them by the key and push them to an array. Below is an example using Array reduce and Object.values to get it down to the two arrays.
var items = [
{"id":1,"date":"2020-02-06","value":131},
{"id":2,"date":"2020-02-06","value":135},
{"id":3,"date":"2020-02-06","value":141},
{"id":4,"date":"2020-02-05","value":151},
{"id":6,"date":"2020-02-05","value":155}
]
var dateGroups = items.reduce( function (dates, item) {
dates[item.date] = dates[item.date] || []
dates[item.date].push(item)
return dates
}, {})
var results = Object.values(dateGroups)
console.log(results)
You could goup by date and get an array of arrays.
var data = [{ id: 1, date: "2020-02-06", value: 131 }, { id: 2, date: "2020-02-06", value: 135 }, { id: 3, date: "2020-02-06", value: 141 }, { id: 4, date: "2020-02-05", value: 151 }, { id: 6, date: "2020-02-05", value: 155 }],
grouped = data.reduce((r, o) => {
var group = r.find(([{ date }]) => date === o.date);
if (!group) r.push(group = []);
group.push(o);
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use reduce to build an object that maps each unique date to its respective data items, having, basically, a group by date:
const data = [{"id":1,"date":"2020-02-06","value":131},{"id":2,"date":"2020-02-06","value":135},{"id":3,"date":"2020-02-06","value":141},{"id":4,"date":"2020-02-05","value":151},{"id":6,"date":"2020-02-05","value":155}];
const groupedData = data.reduce((acc, curr) => ({
...acc,
[curr.date]: [...(acc[curr.date] || []), curr]
}), {});
console.log(groupedData);
We also use above the spread syntax and computed property names to make the code shorter.

Push same multiple objects into multiple arrays based on another value from object

This is a follow up to again Push same multiple objects into multiple arrays.
AFter I create my objects:
let objName = ["object1", "object2", "object3"];
let xyzArr = ["xyz1", "xyz2", "xyz3"];
let theArr = [[], [], []];
let objects = [];
objName.forEach((name, index) => {
objects.push({
xyz: xyzArr[index],
arr: theArr[index]
});
});
And push values using #NickParsons solution:
$.getJSON(json, result => {
result.forEach(elem => {
objects.forEach(obj => {
obj.arr.push({
x: elem.date,
y: elem.val2
});
});
});
});
Here I am adding my objects, i.e. x and y based on no condition. But I want to add it based on if indexOf(obj.xyz) = elem.val1.
THis is my JSON:
[
{
"date": "2019-07-21",
"val1": "xyz1_hello",
"val2": 803310
},
{
"date": "2019-07-22",
"val1": "xyz2_yellow",
"val2": 23418
},
{
"date": "2019-07-22",
"val1": "xyz1_hello",
"val2": 6630
},
{
"date": "2019-07-24",
"val1": "xyz2_yellow",
"val2": 4
},
{
"date": "2019-07-21",
"val1": "xyz3_yo",
"val2": 60984
}
]
Is there a way for me to push values to x and y if obj.xyz is LIKE (indexOF) elem.val1 For example, if indexOf(obj.xyz) = elem.val1, then push their corresponding elem.date and elem.val2 data to obj.arr.
Assuming you have some boolean like(a,b) function that decides if two values are similar or not, and your elements are in elems:
objects.forEach(o =>
elems.forEach(e => {
if(like(o.xyz, e.val1)){
o.arr.push({
x: e.date,
y: e.val2
});
}
}));

how to filter json values to an array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have a json file like this
let myfile = [
{"name":"John","eid":664,"socialid":399,"testid":799},
{"name":"Sam","testid":249,"eid":64,"socialid":80},
{"name":"Albert","eid":422,"testid":20,"socialid":10},
{"name":"Michel","eid":497,"testid":15,"socialid":60}]
from this above json I want to filter all values by it's key name and push it to an array.
expected output is:
"name": ["John", "Sam", "Albert", "Michel"],
"eid": [664, 64, 422, 497],
"testid": [799, 249, 20, 15],
"socialid": [399, 80, 10, 60]
How to make this happen ?
I tried like this
let arr3 = [];
$.each( myfile, function( key, value ) {
if(this.hasOwnProperty('name'))
{
console.log("is there")
arr3.push(value);
}
});
console.log(arr3);
it's not working as expected.
You can use array#reduce to accumulate value corresponding to each key in an object.
let myfile = [{"name":"John","eid":664,"socialid":399,"testid":799}, {"name":"Sam","testid":249,"eid":64,"socialid":80}, {"name":"Albert","eid":422,"testid":20,"socialid":10}, {"name":"Michel","eid":497,"testid":15,"socialid":60}],
result = myfile.reduce((r,o) => {
Object.entries(o).forEach(([key,value]) => {
r[key] = r[key] || [];
r[key].push(value);
});
return r;
},{});
console.log(result);
You can reduce the array into one object:
let myfile = [
{ name: 'John', eid: 664, socialid: 399, testid: 799 },
{ name: 'Sam', testid: 249, eid: 64, socialid: 80 },
{ name: 'Albert', eid: 422, testid: 20, socialid: 10 },
{ name: 'Michel', eid: 497, testid: 15, socialid: 60 },
];
console.log(
myfile.reduce(
(result, item) =>
Object.entries(item).reduce((result, [key, value]) => {
result[key] = result[key] || [];
result[key].push(value);
return result;
}, result),
{},
),
);
You main problem is, you try to access publication which does not exist in the inner objects.
For an inline renaming, you could take an object with the given name as key and the new name as value and take the actual key as default value. Then create a new array, if not exists and push the value to it.
Finally, you get an object with wanted keys with all value from the given data.
var myfile = [{ "name": "John", "eid": 664, "socialid": 399, "testid": 799 }, { "name": "Sam", "testid": 249, "eid": 64, "socialid": 80 }, { "name": "Albert", "eid": 422, "testid": 20, "socialid": 10 }, { "name": "Michel", "eid": 497, "testid": 15, "socialid": 60 }],
replace = { name: 'publication' },
result = myfile.reduce((r, o) => Object.entries(o).reduce((p, [k, v]) => {
k = replace[k] || k;
(p[k] = p[k] || []).push(v);
return p;
}, r), Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Like this?
let json=[
{"name":"John","eid":664,"socialid":399,"testid":799},
{"name":"Sam","testid":249,"eid":64,"socialid":80},
{"name":"Albert","eid":422,"testid":20,"socialid":10},
{"name":"Michel","eid":497,"testid":15,"socialid":60}
]
let output={
publication:[],
eid:[],
testid:[],
socialid:[]
}
for(let i in json){
output.publication.push(json[i].name)
output.eid.push(json[i].eid)
output.testid.push(json[i].testid)
output.socialid.push(json[i].socialid)
}
console.log(output)
I hope that this will help you!

Filter array with object that contains array [closed]

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
}]

Categories

Resources