Comparing values of objects in array and making operation on them - javascript

I'm trying to compare same field elements in objects and restructuring them. I tried to use filter, sort methods but couldn't achieve that. I have an array like this:
const data = [
{
id: 1,
direction: "A",
carry: 6,
distance: 1.41,
},
{
id: 2,
direction: "B",
carry: 5,
distance: 2.83,
},
{
id: 3,
direction: "C",
carry: 4,
distance: 4.24,
},
{
id: 4,
direction: "D",
carry: 3,
distance: 5.66,
},
];
For example: Let's take distance field, they are 1.41, 2.83, 4.24, 5.66. The biggest value (5.66) will be 100%, and other values can be calculated like proportion.
5.66 -> 100%
1.41 -> 25%
2.83 -> 50%
4.24 -> 75%
The carry field follows this way as well. The final result should be like that:
const data = [
{
id: 1,
direction: "A",
carry: 6,
carry_rating: 100,
distance: 1.41,
distance_rating: 25,
},
{
id: 2,
direction: "B",
carry: 5,
carry_rating: 84,
distance: 2.83,
distance_rating: 50,
},
{
id: 3,
direction: "C",
carry: 4,
carry_rating: 67,
distance: 4.24,
distance_rating: 75,
},
{
id: 4,
direction: "D",
carry: 3,
carry_rating: 50
distance: 5.66,
distance_rating: 100,
},
];
I'm struggling for several days. Any support is much appreciated.

A simple way of doing this is to first find the maximum values for distance and carry. Can do this in 1 iteration using array reduce. After that use an array map to add the new fields.
const data = [ { id: 1, direction: "A", carry: 6, distance: 1.41, }, { id: 2, direction: "B",carry: 5, distance: 2.83,}, { id: 3, direction: "C", carry: 4, distance: 4.24, }, { id: 4, direction: "D", carry: 3, distance: 5.66, },];
const {maxCarry,maxDistance} = data.reduce((acc,{carry,distance}) => {
acc.maxCarry = carry < acc.maxCarry ? acc.maxCarry : carry
acc.maxDistance = distance < acc.maxDistance ? acc.maxDistance : distance
return acc
}, {maxCarry:0,maxDistance:0})
const res = data.map((e) => {
const carry_rating = Math.ceil((e.carry/maxCarry)*100)
const distance_rating = Math.ceil((e.distance/maxDistance)*100)
return {carry_rating,distance_rating,...e}
})
console.log(res)

const data = [
{
id: 1,
direction: "A",
carry: 6,
distance: 1.41,
},
{
id: 2,
direction: "B",
carry: 5,
distance: 2.83,
},
{
id: 3,
direction: "C",
carry: 4,
distance: 4.24,
},
{
id: 4,
direction: "D",
carry: 3,
distance: 5.66,
},
];
const maxDistance = Math.max(...data.map(obj => obj.distance))
console.log(maxDistance)
const results = data.map(obj => ({ ...obj, distance_rating: Math.round((obj.distance / maxDistance) * 100) }))
console.log(results)

Related

Get first array objects in every second arrays index

Get first array objects in every second arrays index . Is it possible to get like this given expected output or not possible, we can use for or any other method in JavaScript This is the Two arrays:
let First = [
{lesson: 1},
{lesson: 2},
{lesson: 3}
]
# let Second = [
{
name: "John",
age : 26,
lesson: 1
},
{
name: "Ken",
age : 40,
lesson: 2
},
{
name: "William",
age : 18,
lesson: 3
}
]
Expected output
{
name: "John",
age : 26,
lesson: 1,
lesson: 2,
lesson: 3
},
{
name: "Ken",
age : 40,
lesson: 1,
lesson: 2,
lesson: 3
},
{
name: "William",
age : 18,
lesson: 1,
lesson: 2,
lesson: 3
},
]
you can't have multiple key with différent value in a object but you can do that if you want :
const persons = [{
name: "John",
age : 26,
lesson: [1, 2, 3],
},
{
name: "Ken",
age : 40,
lesson: [1, 2, 3],
},
{
name: "William",
age : 18,
lesson: [1, 2, 3],
},
]
And with code :
for (let i = 0; i < second.length; i++) {
second[i]["lesson"] = [1, 2, 3]
}

Sorting an array based on property value of another array of objects

Let's say I have an array of objects:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
if I have another array like this one :
var disturbed = ["G", "B", "C", "F"];
how can I sort disturbed array based on distance property from the list array like this:
["B", "C", "F", "G"];
Edit: I have tried this code with no success:
items = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
]
sorting = [ 1, 2,3,4,5,6,7,8,9,10 ];
result = []
for (let i = 0; i < items.length; i++){
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && items[i].distance == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[i])
})
}
How can I Sort an array based on the property value of another array of objects
You can use .reduce() to change the list array to object and then sort based on this object.
Demo:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
var sort = list.reduce((acc, cur) => {
acc[cur.name] = cur.distance;
return acc;
}, {});
disturbed.sort((a, b) => sort[a] - sort[b]);
console.log(disturbed)
You can use the sort method to do that
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
disturbed.sort((a, b) => {
var itemA = list.find(item => item.name === a);
var itemB = list.find(item => item.name === b);
return itemA.distance - itemB.distance;
});
disturbed.forEach(function(item) {
document.writeln(item[i])
})
You can use .find() to find the object with the specified name property that matches your elements in distributed. Once you have got this you can then get the distance property and calculate the difference to sort accordingly:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const res = disturbed.sort((a, b) => {
const {distance: d_a} = list.find(({name}) => name === a);
const {distance: d_b} = list.find(({name}) => name === b);
return d_a - d_b;
});
console.log(res);
A more efficient approach would be to create a new Map using .map() and then use .sort() on the keys form the map:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const lut = new Map(list.map(({name, distance}) => [name, distance]));
const res = disturbed.sort((a, b) => lut.get(a) - lut.get(b));
console.log(res);

In javascript, need to perform sum of dynamic array

I have a dynamic array and I need to perform a sum of it.
{ClientName: "A", Alex: 2, Da: 0, Cal: 0}
{ClientName: "b", Alex: 0, Da: 0, Cal: 4}
{ClientName: "c", Alex: 1, Da: 0, Cal: 5}
{ClientName: "d", Alex: 2, Da: 0, Cal: 0}
in this array, client name is fixed but other columns like Alex, Da, Cal are dynamic and will vary. i need to create a generic function in typescript where output will be like this.
{ClientName: "Total", Alex: 5, Da: 0, Cal: 9}
You can try something like this:
Idea:
Uses Object.keys to get all enumerable keys.
Loop over them ans set them to default if not found. Then add current object's value.
Since you need hardcoded value for ClientName, you can set it either in loop or set it after loop.
const data = [
{ClientName: "A", Alex: 2, Da: 0, Cal: 0},
{ClientName: "b", Alex: 0, Da: 0, Cal: 4},
{ClientName: "c", Alex: 1, Da: 0, Cal: 5},
{ClientName: "d", Alex: 2, Da: 0, Cal: 0},
]
const output = data.reduce((acc, item) => {
Object
.keys(item)
.forEach((key) => {
acc[key] = (acc[key] || 0) + item[key]
});
acc.ClientName = 'Total'
return acc;
}, {})
console.log(output)
You could reduce the wanted values.
var data = [{ ClientName: "A", Alex: 2, Da: 0, Cal: 0 }, { ClientName: "b", Alex: 0, Da: 0, Cal: 4 }, { ClientName: "c", Alex: 1, Da: 0, Cal: 5 }, { ClientName: "d", Alex: 2, Da: 0, Cal: 0 }],
total = data.reduce((a, { ClientName, ...b }) => Object.assign(
{},
a,
{ ClientName: 'total' },
...Object.entries(b).map(([k, v]) => ({ [k]: (a[k] || 0) + v }))
));
console.log(total);
Something along these lines should work as long as all keys besides ClientName are defined as numbers
arr.reduce((sumObject, item) => {
Object.keys(item).forEach(key => {
if(key === 'ClientName'){
return false
}
if(!sumObject[key]) {
sumObject[key] = item[key]
} else {
sumObject[key] += item[key]
}
})
return sumObject
}, {ClientName: 'Total'})
You can iterate with reduce to generate single output and to merge the key count you can use Object.keys and map will allow you to iterate over your object keys. Also added one dynamic key Abc: 9 just to verify the result.
const object = [{
ClientName: "A",
Alex: 2,
Da: 0,
Cal: 0
},
{
ClientName: "b",
Alex: 0,
Da: 0,
Cal: 4
},
{
ClientName: "c",
Alex: 1,
Da: 0,
Cal: 5
},
{
ClientName: "d",
Alex: 2,
Da: 0,
Cal: 0,
Abc: 9
},
]
const result = object.reduce((accumulator, currentValue) => {
Object.keys(currentValue).map((indexKey) => {
accumulator[indexKey] = (accumulator[indexKey] || 0) + currentValue[indexKey]
});
accumulator.ClientName = "Total";
return accumulator;
})
console.log(result);
let arr = [
{ClientName: "A", Alex: 2, Da: 0, Cal: 0},
{ClientName: "b", Alex: 0, Da: 0, Cal: 4},
{ClientName: "c", Alex: 1, Da: 0, Cal: 5},
{ClientName: "d", Alex: 2, Da: 0, Cal: 0}
];
let output = arr.reduce((curr, next) => {
return {ClientName: "Total", Alex: (curr.Alex + next.Alex ), Da: (curr.Da + next.Da), Cal: (curr.Cal + next.Cal)};
});
console.log(output);
Check this can get the answer simply

how to concat two object arrays of different size by key using lodash

Stocks: [{
PRN: 1,
PID: 1,
Qty: 3,
SlNos: [1, 2, 3]
}, {
PRN: 1,
PID: 2,
Qty: 4,
SlNos: [10, 11, 12, 13]
}, {
PRN: 2,
PID: 1,
Qty: 3,
SlNos: [4, 5, 6]
}, {
PRN: 2,
PID: 2,
Qty: 4,
SlNos: [14, 15, 16, 17]
}]
I want this array as bellow with Lodash
Stocks: [{
PID: 1,
Qty: 6,
SlNos: [1, 2, 3, 4, 5, 6]
}, {
PID: 2,
Qty: 4,
SlNos: [10, 11, 12, 13, 14, 15, 16, 17]
}]
Here is a solution with _lodash:
var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
const result = _.reduce(stocks, (r, {PRN, ...c}) => {
let _c = _.find(r, {'PID': c.PID})
if(_c)
_c = _.mergeWith(_c, c, (ov, sv, k) => _.includes(['Qty','SlNos'], k) ? _.isArray(sv) ? (ov || []).concat(sv) : _.isNumber(sv) ? sv + (ov || 0) : sv : ov)
else
r.push(c)
return r
}, [])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
We are using reduce with mergeWith (which is the main thing here really) plus a little bit of includes.
Here is a solution without lodash that will do the trick:
var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
const result = stocks.reduce((r, c) => {
_c = r.find(x => x.PID === c.PID)
if (_c) {
_c.PID = c.PID
_c.Qty = _c.Qty + c.Qty
_c.SlNos = _c.SlNos ? _c.SlNos.concat(c.SlNos) : c.SlNos
} else {
r.push(!delete(c.PRN) || c)
}
return r
}, [])
console.log(result)
The idea is to use reduce and first find if we had already that object by PID if so sum the values if not insert to the final array. Since we are going through each record that logic does the trick in one loop.

Use dictionary to filter javascript data object

Say I have a filter:
filter = [ {key: "pl", value: 3}, {key: "sh", value: 2} ]
I want to filter the following javascript object with the above filter conditions:
var data = [
{title: "The Uncertainty of the Poet ",
pl: 3,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 2,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 4,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
...
]
I tried the following with no luck:
var result = data.filter(function(d){
for (item in filter) {
return d.key==d.value;
}
Just another potential option to check if the object meets all the criteria:
data.filter(function(obj) {
return filter.reduce(function(a, f) {
return a && (obj[f.key] === f.value);
}, true);
});
That will work without having to check for hasOwnProperty because of the use of reduce. If you wanted to check for if any of the filter conditions are true, you would change it to
data.filter(function(obj) {
return filter.reduce(function(a, f) {
return a || (obj[f.key] === f.value);
}, false);
});
You can do this way as well:
var filters = [{key: "pl", value: 3}, {key: "sh", value: 2}]
var data = [
{
title: "The Uncertainty of the Poet ",
pl: 2,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 3,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 3,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
]
var result = data.filter((item) => {
for(let i = 0; i < filters.length; ++i) {
let filter = filters[i];
if(item[filter.key] && item[filter.key] === filter.value) {
return true;
}
}
return false;
});
If you want it to match one or the other values, this will work:
match = [ {key: "pl", value: 3}, {key: "sh", value: 2} ]
var result = data.filter(function(d) {
return d.pl === match[0]['value'] || d.sh === match[1]['value']
})
I've changed the name of the array to match to avoid confusion.
You aren't going deep enough with your for in. It is looping over the array and not working with each object in the array
Can use Array#every() to make sure every object in filter array has match in the data object
// filter main data
var result = data.filter(function(dataObj){
// check if all proprties within filter array are a match
return filter.every(function(filterObj){
//compare value of property found in filterObject with value
return dataObj[filterObj.key] === filterObj.value
})
})
console.log(result)
<script>
var filter = [ {key: "pl", value: 2}, {key: "sh", value: 3} ]
var data = [{
title: "The Uncertainty of the Poet ",
pl: 2,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 3,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 4,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
]
</script>

Categories

Resources