Javascript creates new arrays based on conditions - javascript

I have old and entity arrays:
var old = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 100,
"yield": 20,
"worth": 30
},
{
"id": 4,
"entity_type_id": 1,
"product_id": 4,
"name": "test2",
"acreage": 10,
"yield": 20,
"worth": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40
}
]
var entity = [
{"id": 1, "name": "a1"},
{"id": 2, "name": "a2"},
{"id": 3, "name": "a3"}
]
I hope to get the following data:
var newArr = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 110,
"yield": 40,
"worth": 30,
"entity_type_1": 2, // The total amount of entity_type_id (entity_type_id: 1)
"entity_type_2": 0,
"entity_type_3": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40,
"entity_type_1": 0,
"entity_type_2": 0,
"entity_type_3": 1 // The total amount of entity_type_id (entity_type_id: 3)
}
]
console.log(newArr)
I tried the following code and got some data. I'm not sure if there will be any exceptions or errors.
What's more, I don't know how to deal with the entity array data. Can someone help me solve this problem and get the result I expect?
Thank you very much !
function mergeArr(arr) {
const temp = []
arr.forEach((dataItem) => {
if (temp.length) {
let filterValue = temp.filter((items) => {
return items.product_id === dataItem.product_id
})
if (filterValue.length) {
temp.forEach((n) => {
if (n.product_id === filterValue[0].product_id) {
n.yield = dataItem.yield + filterValue[0].yield
n.acreage = dataItem.acreage + filterValue[0].acreage
n.worth = dataItem.worth + filterValue[0].worth
}
})
} else {
temp.push(dataItem)
}
} else {
temp.push(dataItem)
}
})
return temp
}

Youi could find the object and sum the wanted properties. For entity take another loop and map new entries and build a new object from it for spreading.
var old = [{ id: 3, entity_type_id: 1, product_id: 4, name: "test1", acreage: 100, yield: 20, worth: 30 }, { id: 4, entity_type_id: 1, product_id: 4, name: "test2", acreage: 10, yield: 20, worth: 0 }, { id: 5, entity_type_id: 3, product_id: 5, name: "test3", acreage: 20, yield: 20, worth: 40 }],
entity = [{ id: 1, name: "a1" }, { id: 2, name: "a2" }, { id: 3, name: "a3" }],
entityTypes = Object.fromEntries(entity.map(({ id }) => ['entity_type_' + id, 0])),
result = old.reduce((r, o) => {
let temp = r.find(q => q.product_id === o.product_id);
if (!temp) r.push(temp = { ... o, ...entityTypes });
else ['acreage', 'yield', 'worth'].forEach(k => temp[k] += o[k]);
temp['entity_type_' + o.entity_type_id]++;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Find average value within different JSON objects

I have a JSON object which is as follows, it consists of an id, and object measurements.
Object measurements consists of Tastiness which has its respective taste for each level, such as level 25,50, and 100. I'm trying to combine the tastiness into 1 value with the average of each taste level (for example total of sourness / objectMeasurements number)
"objectId": "de8e783a-1a13-42be-b1b2-1bc7be24b511"
"objectMeasurements": [
{
"id": "f986cb0d-a9f2-4d8f-ad2f-9ff46e097764",
"data": {
"scale": 5,
"tastiness": [
{
"level": 100,
"sourness": 4,
"freshness": 5,
"sweetness": 3
},
{
"level": 25,
"sourness": 4,
"freshness": 3,
"sweetness": 5
},
{
"level": 50,
"sourness": 3,
"freshness": 5,
"sweetness": 5
}
]
},
},
{
"id": "12efc22b-ff69-4248-8b25-4ed8981089df",
"data": {
"scale": 5,
"tastiness": [
{
"level": 100,
"sourness": 3,
"freshness": 5,
"sweetness": 5
},
{
"level": 25,
"sourness": 5,
"freshness": 4,
"sweetness": 4
},
{
"level": 50,
"sourness": 4,
"freshness": 5,
"sweetness": 3
}
]
}
}
]
How is it possible for me to combine the data tastiness and get the average of each property, into 1 object measurement such as something like this
"objectId": "de8e783a-1a13-42be-b1b2-1bc7be24b511"
"objectMeasurements": [
{
"id": "someId",
"data": {
"scale": 5,
"tastiness": [
{
"level": 100,
"sourness": 3.5,
"freshness": 2,
"sweetness": 4
},
{
"level": 25,
"sourness": 4.5,
"freshness": 3.5,
"sweetness": 4.5
},
{
"level": 50,
"sourness": 3.5,
"freshness": 2,
"sweetness": 4
}
]
},
},
const input = {
"objectId": "de8e783a-1a13-42be-b1b2-1bc7be24b511",
"objectMeasurements": [{
"id": "f986cb0d-a9f2-4d8f-ad2f-9ff46e097764",
"data": {
"scale": 5,
"tastiness": [{
"level": 100,
"sourness": 4,
"freshness": 5,
"sweetness": 3
}, {
"level": 25,
"sourness": 4,
"freshness": 3,
"sweetness": 5
}, {
"level": 50,
"sourness": 3,
"freshness": 5,
"sweetness": 5
}]
},
}, {
"id": "12efc22b-ff69-4248-8b25-4ed8981089df",
"data": {
"scale": 5,
"tastiness": [{
"level": 100,
"sourness": 3,
"freshness": 5,
"sweetness": 5
}, {
"level": 25,
"sourness": 5,
"freshness": 4,
"sweetness": 4
}, {
"level": 50,
"sourness": 4,
"freshness": 5,
"sweetness": 3
}]
}
}]
}
let res = {}
input.objectMeasurements.map(obj => {
obj.data.tastiness.map((m) => {
const keys = Object.keys(m);
keys.map(key => {
if (key !== 'level') {
if (!res[(m.level)].count[key]) {
res[(m.level)].count[key] = res[(m.level)].totals[key] = 0;
}
res[(m.level)].count[key]++;
res[(m.level)].totals[key] += m[key];
} else {
if (!res[(m.level)]) {
res[(m.level)] = {
count: {},
totals: {}
}
}
}
});
});
});
let tastiness = [];
Object.keys(res).reverse().map(levelKey => {
let avg = {};
avg.level = +levelKey;
Object.keys(res[levelKey].count).map(tasteKey => {
avg[tasteKey] = res[levelKey].totals[tasteKey] / res[levelKey].count[tasteKey];
});
tastiness.push(avg);
});
input.objectMeasurements = tastiness;
console.log(input);

Formatting of JavaScript Objects, Showing Sub Products under Products

I have an array of objects for products I want to show objects that have a parent ID under their parent object with property called subproduct
I have a array object like
let products = [{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "1450",
"name": "Paypal"
},
{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "1451",
"name": "Payments"
}
]
I want to format it in the following way
"products": [{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "14",
"name": "Paypal"
"sub-products": [{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "15",
"name": "Paypal-Payments"
}]
}]
This will work
let products = [
{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "1450",
"name": "Paypal"
},
{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "1451",
"name": "Payments"
}
]
let formated = [];
formated = products.filter(product => product.parent_id == null);
formated.forEach(formatedproduct=>{
products.forEach(product =>{
if(product.parent_id == formatedproduct.id){
if(!formatedproduct.sub_products )
{
formatedproduct.sub_products = [];
}
product.name = formatedproduct.name +' '+product.name;
formatedproduct.sub_products.push(product);
}
});
})
console.log(formated);
You can use a combination of map and reduce
const grouped = [
...products
.sort((a, b) => a.parent_id - b.parent_id)
.reduce((a, b) => a.set(b.parent_id || b.id, (a.get(b.parent_id) || []).concat(b)), new Map())
.values()
]
.map(([f, ...rest]) => (f.sub_products = rest, f));
console.log(grouped);
<script>
const products = [{
'id': 30,
'service_provider_id': 4,
'parent_id': null,
'status_id': 1,
'code': '1450',
'name': 'Paypal'
},
{
'id': 31,
'service_provider_id': 4,
'parent_id': 30,
'status_id': 1,
'code': '1451',
'name': 'Payments'
},
{
'id': 32,
'service_provider_id': 4,
'parent_id': null,
'status_id': 1,
'code': '1450',
'name': 'Paypal'
},
{
'id': 33,
'service_provider_id': 4,
'parent_id': 32,
'status_id': 1,
'code': '1451',
'name': 'Payments'
}
];
</script>

convert json array based on id

I want to convert array to another array based on sID and pID properties
the array I have is:
data = [{
{
"sID": 10,
"pID": 5,
"Sum": 9300,
"class": "one",
},{
"sID": 10,
"pID": 5,
"Sum": 2200,
"class": "two",
},{
"sID": 10,
"pID":6 ,
"Sum": 4600,
"class": "one",
},{
"sID": 10,
"pID": 6,
"Sum": 5300,
"class": "two"
}]
I want to create a data in below format
[{"sID":10,"pID":5,"one":9300,"two":2200},
{"sID":10,"pID":6,"one":4600,"two":5300}]
is there a way to do this?
You could take a hash table for same group of keys and assign the sum of the values to the result.
var data = [{ sID: 10, pID: 5, Sum: 9300, class: "one" }, { sID: 10, pID: 5, Sum: 2200, class: "two" }, { sID: 10, pID: 6, Sum: 4600, class: "one" }, { sID: 10, pID: 6, Sum: 5300, class: "two" }],
keys = ['sID', 'pID'],
result = Object.values(data.reduce((h, o) => {
var key = keys.map(k => o[k]).join('|');
if (!h[key]) {
h[key] = Object.assign(...keys.map(k => ({ [k]: o[k] })));
}
h[key][o.class] = (h[key][o.class] || 0) + o.Sum;
return h;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
more basic :
const
data = [
{ "sID": 10, "pID": 5, "Sum": 9300, "class": "one" }
, { "sID": 10, "pID": 5, "Sum": 2200, "class": "two" }
, { "sID": 10, "pID": 6, "Sum": 4600, "class": "one" }
, { "sID": 10, "pID": 6, "Sum": 5300, "class": "two" }
];
var Result = [];
data.forEach(e=>{
let idx = Result.findIndex( k=> k.sID===e.sID && k.pID===e.pID );
if (idx<0)
{
idx = Result.length;
Result.push( { "sID":e.sID, "pID":e.pID });
}
Result[idx][e.class] = e.Sum;
})
console.log( Result )

Trying to merge two arrays

Below is my json stored in :
$scope.regions = [];
{
"id": 100,
"regions": [
{
"id": 10,
"name": "Abc",
"rank": 0,
},
{
"id": 20,
"name": "Pqr",
"rank": 1,
},
{
"id": 30,
"name": "Lmn",
"rank": 2,
},
{
"id": 40,
"name": "xyz",
"rank": 3,
},
{
"id": 50,
"name": "GGG",
"rank": 4,
},
{
"id": 60,
"name": "YYY",
"rank": 5,
}
]
}
This is my another json stored in :
$scope.regionList = [];
var highestOrder = 3;
"regions": [
{
"id": 40,
"name": "xyz",
"rank": 0,
},
{
"id": 50,
"name": "GGG",
"rank": 1,
},
{
"id": 60,
"name": "YYY",
"rank": 2,
}
Now I want to merge $scope.regionList in to $scope.regions but for those records which are matching in both $scope.regionList and $scope.regions I would like to replace records of $scope.regions with $scope.regionList (only common records from both list).
And first non matching records from $scope.regionList will have order start using highestOrder and will keep incrementing for each non-matching records so final output will be like below :
Expected output :
"regions": [
{
"id": 10,
"name": "Abc",
"rank": 3,
},
{
"id": 20,
"name": "Pqr",
"rank": 4,
},
{
"id": 30,
"name": "Lmn",
"rank": 5,
},
{
"id": 40,
"name": "xyz",
"rank": 0,
},
{
"id": 50,
"name": "GGG",
"rank": 1,
},
{
"id": 60,
"name": "YYY",
"rank": 2,
}
As Abc is is the first non matching record so it will have order 3 and rest other will have order no from 3 i.e 4,5 6, etc.
My code:
var highestOrder = 3;
var found = false;
for (var i = 0; i < $scope.regions.length; i++) {
if ($scope.regions[i].id == 100) {
found = true;
for (var j = 0; j < $scope.regionList.length; j++) {
for (var k = 0; k < $scope.regions[i].regions.length; k++) {
if ($scope.regions[i].regions[k].id == $scope.regionList[j].id) {
$scope.regions[i].regions[k].rank = $scope.regionList[j].rank;
}
else {
$scope.regions[i].regions[k].rank = highestOrder;
highestOrder = highestOrder + 1;
}
}
}
}
if (found)
break;
}
var regions = {
"id": 100,
"regions": [{
"id": 10,
"name": "Abc",
"rank": 0,
},
{
"id": 20,
"name": "Pqr",
"rank": 1,
},
{
"id": 30,
"name": "Lmn",
"rank": 2,
},
{
"id": 40,
"name": "xyz",
"rank": 3,
},
{
"id": 50,
"name": "GGG",
"rank": 4,
},
{
"id": 60,
"name": "YYY",
"rank": 5,
}
]
}
var highestOrder = 3;
var found = false;
var regionList = [{
"id": 40,
"name": "xyz",
"rank": 0,
},
{
"id": 50,
"name": "GGG",
"rank": 1,
},
{
"id": 60,
"name": "YYY",
"rank": 2
}
]
for (var i = 0; i < regions.length; i++) {
if (regions[i].id == 100) {
found = true;
for (var j = 0; j < regionList.length; j++) {
for (var k = 0; k < regions[i].regions.length; k++) {
if (regions[i].regions[k].id == regionList[j].id) {
regions[i].regions[k].rank = regionList[j].rank;
} else {
regions[i].regions[k].rank = highestOrder;
highestOrder = highestOrder + 1;
}
}
}
}
if (found)
break;
}
console.log(regions)
You could use a hash table and build it with the elements of the array for updating.
Then iterate regions and update rank with either the hash's rank or with highestOrder. Increment highestOrder after assigning.
var $scope = { regions: [{ id: 100, regions: [{ id: 10, name: "Abc", rank: 0, }, { id: 20, name: "Pqr", rank: 1, }, { id: 30, name: "Lmn", rank: 2, }, { id: 40, name: "xyz", rank: 3, }, { id: 50, name: "GGG", rank: 4, }, { id: 60, name: "YYY", rank: 5, }] }] },
regionsUpdate = [{ id: 40, name: "xyz", rank: 0, }, { id: 50, name: "GGG", rank: 1, }, { id: 60, name: "YYY", rank: 2, }],
regionsId = 100,
highestOrder = 3,
hash = Object.create(null);
regionsUpdate.forEach(function (a) {
hash[a.id] = a;
});
$scope.regions.some(function (a) {
if (a.id === regionsId) {
a.regions.forEach(function (b) {
b.rank = hash[b.id] ? hash[b.id].rank : highestOrder++;
});
return true;
}
});
console.log($scope);
.as-console-wrapper { max-height: 100% !important; top: 0; }

lodash merge and combine objects

I have an array of objects as below that I read from my database using sequelize ORM:
I want to have all my videos from a section, but the better I can return using sequelize is :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
}
},
{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}
}]
Is there a way to merge and combine the objects in my array to obtain something like this :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": [{
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
},{
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}]
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": [{
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
},{
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}]
}
The function that approach the most is _.mergeWith(object, sources, customizer) but the main problem I have is that I have on object and need to merge this object.
In plain Javascript, you can use Array#forEach() with a temporary object for the arrays.
var data = [{ id: 2, name: "Ru", subsection: 1, Video: { id: 11, source: "sourrrccrsss22222", VideoSubSection: 2 } }, { id: 2, name: "Ru", subsection: 1, Video: { id: 12, source: "sourrrccrsss111", VideoSubSection: 2 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 13, source: "sourrrcc", VideoSubSection: 1 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 14, source: "sourrrcc", VideoSubSection: 1 } }],
merged = function (data) {
var r = [], o = {};
data.forEach(function (a) {
if (!(a.id in o)) {
o[a.id] = [];
r.push({ id: a.id, name: a.name, subsection: a.subsection, Video: o[a.id] });
}
o[a.id].push(a.Video);
});
return r;
}(data);
document.write('<pre>' + JSON.stringify(merged, 0, 4) + '</pre>');
Maybe try transform():
_.transform(data, (result, item) => {
let found;
if ((found = _.find(result, { id: item.id }))) {
found.Video.push(item.Video);
} else {
result.push(_.defaults({ Video: [ item.Video ] }, item));
}
}, []);
Using reduce() would work here as well, but transform() is less verbose.
You can do it this way (test is your db output here)
var result = [];
var map = [];
_.forEach(test, (o) => {
var temp = _.clone(o);
delete o.Video;
if (!_.some(map, o)) {
result.push(_.extend(o, {Video: [temp.Video]}));
map.push(o);
} else {
var index = _.findIndex(map, o);
result[index].Video.push(temp.Video);
}
});
console.log(result); // outputs what you want.

Categories

Resources