React - Define greater string between objects - javascript

I am calculating the average score of each object ( team ) in my array.
This is my data structure:
const scores = [
{ day: "1", Barcelona: 1, Real: 3, Valencia: 0 },
{ day: "2", Barcelona: 4, Real: 6, Valencia: 3 },
{ day: "3", Barcelona: 7, Real: 7, Valencia: 3 },
{ day: "4", Barcelona: 7, Real: 8, Valencia: 6 }
];
This is how i calculate the average
const getAverage = team => {
if (isNaN(scores[0][team])) return null;
return scores.map(x => x[team]).reduce((a, c) => a + c) / scores.length;
};
I need to establish the object team with the greater number which is the stronger team. How can i do that ?
The stronger team is the team with the higher average.
Here i have done a prototype to reproduce the scenario: https://codesandbox.io/s/recharts-examples-y0y7q

Get the maxAverage from array of teams like so:
this.state = {
homeCity: "Barcelona",
awayCity: "Valencia"
}
const scores = [
{ day: "1", Barcelona: 1, Real: 3, Valencia: 0 },
{ day: "2", Barcelona: 4, Real: 6, Valencia: 3 },
{ day: "3", Barcelona: 7, Real: 7, Valencia: 3 },
{ day: "4", Barcelona: 7, Real: 8, Valencia: 6 }
];
const getAverage = team => {
if (isNaN(scores[0][team])) return null;
return scores.map(x => x[team]).reduce((a, c) => a + c) / scores.length;
};
const maxAverage = teams => {
return teams.map(team => {
return {
team:team,
avg: getAverage(team)
}
}).reduce((a,b)=>a.avg>b.avg?a:b).team
}
console.log(maxAverage([this.state.homeCity,this.state.awayCity]));

You can extend your code, loop through the first element to get all the keys, filter out day key so we left with all the team name, map through team names and get average and then sort
const scores = [
{ day: "1", Barcelona: 1, Real: 3, Valencia: 0 },
{ day: "2", Barcelona: 4, Real: 6, Valencia: 3 },
{ day: "3", Barcelona: 7, Real: 7, Valencia: 3 },
{ day: "4", Barcelona: 7, Real: 8, Valencia: 6 }
];
const getAverage = team => {
if (isNaN(scores[0][team])) return null;
return scores.map(x => x[team]).reduce((a, c) => a + c) / scores.length
};
let stronger = Object.entries(scores[0])
.filter(([key, value]) => key !== 'day')
.map(([key, value]) => [key, getAverage(key)])
.sort((a, b) => b[1] - a[1])
console.log(stronger)

Related

map array of objects based on set of properties

Suppose I have an object:
let array = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
then I have a dictionary:
const columns = [
{ key: 'a', value: 'a' },
{ key: 'b', value: 'b' },
]
I want to filter out properties that are not defined in columns.
I have tried
array.map((x) => ({"a": x.a, "b": x.b}))
Is there a way to use the data defined in columns instead of manually typing all the properties?
Desired output:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
You could map entries and get the new objects.
let
array = [{ a: 1, b: 5, c: 9 }, { a: 2, b: 6, c: 10 }, { a: 3, b: 7, c: 11 }, { a: 4, b: 8, c: 12 }],
columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }],
keys = columns.map(({ key }) => key),
result = array.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use this.
This uses just an array to hold the desired columns because I don't get why you would use a dictionary with key and value being the same.
let array = [
{ a: 1, b: 5, c: 9 },
{ a: 2, b: 6, c: 10 },
{ a: 3, b: 7, c: 11 },
{ a: 4, b: 8, c: 12 },
];
const desiredColumns = ["a", "b"];
const transformed = array.map(item => {
const obj = {};
desiredColumns.forEach(col => {
if(col in item){
obj[col] = item[col];
}
})
return obj;
})
console.log(array);
console.log(transformed)
Another, slightly less direct way using map() and reduce():
Create an array with all the keys we'll keep
Reduce the array to get the desired result
Add current key + value if key keep array
const array = [{a: 1, b: 5, c: 9}, {a: 2, b: 6, c: 10}, {a: 3, b: 7, c: 11}, {a: 4, b: 8, c: 12} ];
const columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }, ];
const toKeep = columns.map(({ key }) => key).flat();
const result = array.map(a =>
Object.keys(a)
.reduce((prev, cur) => (toKeep.includes(cur)) ? { ...prev, [cur]: a[cur] } : prev, {})
);
console.log(result);
Result:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]

Calculate Percentage in Java Script and Output Result

I am trying to use below Script to Get the Average of Disconnect Devices .The results are output in group for each Test Customer .
var dataObject = [{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 7,
"Disconnected_Devices": 1,
"Total_Devices": 8
},
{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 6,
"Disconnected_Devices": 2,
"Total_Devices": 8
},
{
"Customer_Nbr": "12",
"Customer_Name": "Test3",
"Connected_Devices": 8,
"Disconnected_Devices": 2,
"Total_Devices": 10
}
];
groups = dataObject.reduce(function(r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function(k) {
groups[k].Average = Math.round(groups[k].Disconnected_Devices / groups[k].Average);
return groups[k];
});
console.log(result)
Now I also want grouped output to have a percentage calculation which would be result/Total_Devices * 100 .
Output Should be Something like Assuming Total_Devices Count is constant in Input data -
[
{
Customer_Nbr: '13',
Customer_Name: 'Test1',
Connected_Devices: 7,
Disconnected_Devices: 3,
Total_Devices: 8,
Average: 2
Percent: 25
},
{
Customer_Nbr: '12',
Customer_Name: 'Test3',
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
Average: 2
Percent: 20
}
]
Something like this maybe?
var dataObject = [
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 7,
Disconnected_Devices: 1,
Total_Devices: 8,
},
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 6,
Disconnected_Devices: 2,
Total_Devices: 8,
},
{
Customer_Nbr: "12",
Customer_Name: "Test3",
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
},
];
groups = dataObject.reduce(function (r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function (k) {
groups[k].Average = Math.round(
groups[k].Disconnected_Devices / groups[k].Average
);
groups[k].percentage = (groups[k].Average/groups[k].Total_Devices) * 100;
return groups[k];
});
console.log(result);

Flatten nested objects, keeping the properties of parents

I have a data structure that has this shape:
[
{
a: "x",
val: [
{ b: "y1", val: [1, 2, 3] },
{ b: "y2", val: [4, 5, 6] },
],
},
];
An example with 3 levels:
[
{
a: "x",
val: [
{ b: "y1", val: [
{c: "z1", val: [1, 2]}
] },
{ b: "y2", val: [
{ c: "z2", val: [3, 4] },
{ c: "z3", val: [5, 6, 7] },
{ c: "z4", val: [8] }
] },
],
},
];
Each object always has the same level of nesting, and I know the max depth of nesting in advance. We also know the names of the keys in advance: we know that the key at level 1 will be named a, the one at level 2 will be named b, and so on.
I'm looking to create a function that transforms the first example into:
[
{
a: "x",
b: "y1",
val: [1, 2, 3],
},
{
a: "x",
b: "y2",
val: [4, 5, 6],
},
];
that is, a flat array with values and keys inherited from parents.
I've got a solution which works for the first example:
const res = [
{
a: "x",
val: [
{ b: "y1", val: [1, 2, 3] },
{ b: "y2", val: [4, 5, 6] },
],
},
].flatMap((x) => x.val.flatMap((d) => ({ a: x.a, ...d })));
console.log(res);
but I'm struggling to turn it into a recursive function.
Thank you in advance for your help!
You could have a look to the arrays and if no objects inside return an object, otherwise map val property by storing other properties.
const
isObject = o => o && typeof o === 'object',
flat = array => {
if (!array.every(isObject)) return { val: array };
return array.flatMap(({ val, ...o }) => {
const temp = flat(val);
return Array.isArray(temp)
? temp.map(t => ({ ...o, ...t }))
: { ...o, ...temp };
});
},
data0 = [{ a: "x", val: [{ b: "y1", val: [1, 2, 3] }, { b: "y2", val: [4, 5, 6] }] }],
data1 = [{ a: "x", val: [{ b: "y1", val: [{ c: "z1", val: [1, 2] }] }, { b: "y2", val: [{ c: "z2", val: [3, 4] }, { c: "z3", val: [5, 6, 7] }, { c: "z4", val: [8] }] }] }];
console.log(flat(data0));
console.log(flat(data1))
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to loop values in an array with similar values but distinctively?

var items =[
{ID:1,day:'mon',val1:10,val2:20,val3:10},
{ID:2,day:'mon',val1:11,val2:70,val3:55},
{ID:3,day:'mon',val1:15,val2:27,val3:37},
{ID:4,day:'teu',val1:9,val2:17,val3:11}
]
var workDays = ['mon','teu']
I need to loop through the item array above.. and append the data elsewhere in the following form:
--loop block starts--
Day:// from workDays
Values:// from item array
--loop block ends---
Final result Should be something like
Day:'mon'
Values:10,20,10...(display all values corresponding to 'mon' in item array
How do i go about that?
You can use ES6 destructuring and easily achieve what you want:
var items = [{
ID: 1,
day: 'mon',
val1: 10,
val2: 20,
val3: 10
},
{
ID: 2,
day: 'mon',
val1: 11,
val2: 70,
val3: 55
}, {
ID: 3,
day: 'mon',
val1: 15,
val2: 27,
val3: 37
}, {
ID: 4,
day: 'teu',
val1: 9,
val2: 17,
val3: 11
}
]
var workDays = ['mon', 'teu']
const result = workDays.map(day => {
const dayItems = items.filter(item => item.day === day);
const values = dayItems.reduce((a, {
val1,
val2,
val3
}) => [...a, val1, val2, val3], []);
return {
Day: day,
Values: values,
};
});
console.log(result);
You could achieve it using map, filter and flat. something like this
const items = [
{"ID": 1, "day": "mon", "val1": 10, "val2": 20, "val3": 10},
{"ID": 2, "day": "mon", "val1": 11, "val2": 70, "val3": 55},
{"ID": 3, "day": "mon", "val1": 15, "val2": 27, "val3": 37},
{"ID": 4, "day": "teu", "val1": 9, "val2": 17, "val3": 11}
];
const workDays = ["mon", "teu"];
const result = workDays.map(day => {
return {
"Day": day,
"values": items.filter(item => item.day === day).map(i => {
return [i.val1, i.val2, i.val3];
}).flat()
};
});
console.log(result);

Array.reduce on a multidimensional array to array of objects

In my poker app I have an array of hands, each hand being array of randomly selected card objects with value and suit:
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
To prepare the hands for evaluation I want to use Array.reduce to return an array of hand objects. So the output would be:
[
{
values: [5, 4, 6, 11, 12],
suits: ['s', 's', 'c', 'd', 'c']
},
{
values: [9, 12, 8, 12, 2],
suits: ['d', 'h', 'c', 's', 's']
},
{
values: [4, 6, 10, 3, 7],
suits: ['h', 's', 'c', 'd', 'd']
}
]
I tried implementing this with nested forEach's, but its failing and I don't know why. I have two console.log's within which output as expected, but in the end hands is identical to the input.
let temp = []
hands.forEach((el) => {
temp = el
el = {}
el.values = []
el.suits = []
console.log(el) //expected output
temp.forEach((obj) => {
el.values.push(obj.value)
el.suits.push(obj.suit)
console.log(el) //expected output
})
})
console.log(hands) //same as original
You have to be thinking about the shape of your input data (DATA) and output (DATA')
Note 1:1 relationship between HAND and HAND' meaning we will use Array.prototype.map for one transformation. On the other hand, CARD has a N:1 relationship with HAND' meaing we will use Array.prototype.reduce for that transformation
So keep in mind while we're working, we will be doing a map and a reduce
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
let output =
data.map(cards =>
cards.reduce(({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
}), {values: [], suits: []}))
console.log(output)
Now of course that looks a little dense so it would be nice if we could dial down the complexity a bit. By making some curried adapters for map and reduce we can express a function that performs your transformation quite nicely
const data =
[ [ { value: 5, suit: 's' },
{ value: 4, suit: 's' },
{ value: 6, suit: 'c' },
{ value: 11, suit: 'd' },
{ value: 12, suit: 'c' } ],
[ { value: 9, suit: 'd' },
{ value: 12, suit: 'h' },
{ value: 8, suit: 'c' },
{ value: 12, suit: 's' },
{ value: 2, suit: 's' } ],
[ { value: 4, suit: 'h' },
{ value: 6, suit: 's' },
{ value: 10, suit: 'c' },
{ value: 3, suit: 'd' },
{ value: 7, suit: 'd' } ] ]
const map = f => xs => xs.map(f)
const reduce = f => y => xs => xs.reduce(f, y)
const handAppendCard = ({values, suits}, {value, suit}) => ({
values: [...values, value],
suits: [...suits, suit]
})
const makeHands =
map (reduce (handAppendCard) ({values:[], suits:[]}))
let output = makeHands (data)
console.log(output)
That's just one way to approach the problem. I hope you were able to learn something from it ^_^
There you go - a solution using nested Array.prototype.reduce functions:
var array=[[{value:5,suit:'s'},{value:4,suit:'s'},{value:6,suit:'c'},{value:11,suit:'d'},{value:12,suit:'c'}],[{value:9,suit:'d'},{value:12,suit:'h'},{value:8,suit:'c'},{value:12,suit:'s'},{value:2,suit:'s'}],[{value:4,suit:'h'},{value:6,suit:'s'},{value:10,suit:'c'},{value:3,suit:'d'},{value:7,suit:'d'}]];
var result = array.reduce(function(p, c) {
p.push(c.reduce(function(a, b) {
a.values.push(b.value);
a.suits.push(b.suit);
return a;
}, {values: [],suits: []}));
return p;
},[]);
console.log(result);
.as-console-wrapper {top: 0;max-height: 100%!important;}
You can use reduce flat to extract nested arrays. If you pass Infinity, no matter how deep they are, they'll be extracted.
const result = flatten([1,2,[3,4],[5,6,7]]) // result: [1,2,3,4,5,6,7]
Everything becomes one-dimensional array
Here's a simple solution with string concat and reduce. You could try something like:
var reduced = [];
//here a is your initial array
for(var i=0; i<a.length;i++){
reduced.push(a[i].reduce(function(prev,curr){
var obj={value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj}));
}
console.log(reduced)
EDIT: As per #Barmar comment this returns string. If you want an array you could do:
for(var i=0; i<a.length;i++){
var tempElm =a[i].reduce(function(prev,curr) {
var obj= {value:prev.value+','+curr.value,suit:prev.suit+','+curr.suit};return obj});
tempElm['value'] = tempElm['value'].split();
tempElm['suit']= tempElm['suit'].split();
reduced.push(tempElm);
}
console.log(reduced)
EDIT 2: With the fair criticism for the above fix (which adds an over head of converting string to array) You could directly create array instead as follows:
var reduced = [];
for(var i=0; i<a.length;i++){
var valArray = []; var suitArray=[];
var tempElm = a[i].reduce(function(prev,curr) {
valArray.push(curr.value);suitArray.push(curr.suit);
var obj= {value:valArray,suit:suitArray};
return obj;
},null);
console.log(reduced)

Categories

Resources