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);
I have this array of objects that I want to filter based on these rules:
If more than one object has team and day are the same, remove the objects with the lowest Level
but if more than one object with same lowest Level then remove the one with the lowest strength
if there's still more than one remove one with the lowest ability.
Thought about creating a new array after each condition, then, also tried to come up with a way of doing it with all the conditions, and I am so lost with it I don't know where I'm up to.
I also tried creating an empty array and pushing the objects that meet the rules into it, but ended up having to meet all the rules anyway and was still just as complicated.
const players = [
{ Level: 1, team: 'green', strength: 2, ability: 2, day: 1 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 2 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 3 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 3 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 4 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 4 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 5 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 5 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 4 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 5 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 1 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 2 },
{ Level: 2, team: 'red', strength: 2, ability: 3, day: 1 },
{ Level: 2, team: 'silver', strength: 2, ability: 3, day: 1 },
{ Level: 2, team: 'red', strength: 2, ability: 3, day: 2 },
{ Level: 2, team: 'silver', strength: 2, ability: 3, day: 2 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 1 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 1 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 2 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 3 }
];
The approach I followed:
The general approach I follow is to compare between two candidates instead of selecting the best one between multiple candidates. This approach looks easier for me to reason.
The process does:
Sort records by key (team + day) so same key records are adjacents and it is easy to iterate.
Using reduce compare the current element with the last element of the partial result to see which one is higher in priority. When we have a higher priority we update the last element of result, otherwise we add the current element to result.
Higher priority is true when for the same key the current has higher priority following your requirements. I like the way this logic is isolated and implemented in isCandidateHigherPriorytyThanResult function. If you need to change the logic it would quite easy to adapt.
const players=[{Level:1,team:"green",strength:2,ability:2,day:1},{Level:1,team:"red",strength:2,ability:2,day:2},{Level:1,team:"red",strength:2,ability:2,day:3},{Level:1,team:"silver",strength:2,ability:2,day:3},{Level:1,team:"red",strength:2,ability:2,day:4},{Level:1,team:"silver",strength:2,ability:2,day:4},{Level:1,team:"red",strength:2,ability:2,day:5},{Level:1,team:"silver",strength:2,ability:2,day:5},{Level:2,team:"red",strength:2,ability:4,day:4},{Level:2,team:"red",strength:2,ability:4,day:5},{Level:1,team:"silver",strength:2,ability:2,day:1},{Level:1,team:"silver",strength:2,ability:2,day:2},{Level:2,team:"red",strength:2,ability:3,day:1},{Level:2,team:"silver",strength:2,ability:3,day:1},{Level:2,team:"red",strength:2,ability:3,day:2},{Level:2,team:"silver",strength:2,ability:3,day:2},{Level:2,team:"red",strength:2,ability:4,day:1},{Level:3,team:"red",strength:3,ability:4,day:1},{Level:3,team:"red",strength:3,ability:4,day:2},{Level:3,team:"red",strength:3,ability:4,day:3}];
const key = (teamObj) =>{
return teamObj.team + teamObj.day
}
const sortByKey =
(a,b)=>{
if(key(a) > key(b)) return 1
else
if(key(a) < key(b)) return -1
else return 0
}
// return true if obj is {} otherwise is false
const isAnEmptyObject = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object
const isCandidateHigherPriorytyThanResult =
(candidate, result) =>{
if(key(result) !== key(candidate)) return false
if(candidate.level > result.level) return true
if(candidate.level < result.level) return false
if(candidate.strength > result.strength) return true
if(candidate.strength < result.strength) return false
if(candidate.ability > result.ability) return true
return false
}
const reducer = (result, current) =>{
const resultLast = result[result.length -1]
// To accomodate for first iteration were result value is: {[]}
if(isAnEmptyObject(resultLast))
{
result[result.length -1]= {...current}
return result
}
if(isCandidateHigherPriorytyThanResult(current, resultLast))
{
result[result.length -1] = {...current}
return result
}else
{
return result.concat(current)
}
}
const teamsResult =
players
.sort(sortByKey) //?
.reduce(reducer,[{}])
console.log(teamsResult)
Group players by team and ``day
Iterate over each category:
If only one player in the category, keep it
Else, define a set of filtering strategy to use it according to the rules you mentioned
Get the number of players with the lowest level in this category, if only one player found, set filtering condition to remove it
Else, if more than one player found having the lowest level, get the count of those having the lowest strength among them
If only one player found in this result set filtering conditions to remove it
Else, set the filtering conditions to remove the players with the lowest ability among them
At the end of each iteration, you will need to filter out the players according to the filtering conditions. Lastly, return the remaining players in each category in one list.
const players = [
{ Level: 1, team: 'green', strength: 2, ability: 2, day: 1 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 2 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 3 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 3 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 4 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 4 },
{ Level: 1, team: 'red', strength: 2, ability: 2, day: 5 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 5 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 4 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 5 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 1 },
{ Level: 1, team: 'silver', strength: 2, ability: 2, day: 2 },
{ Level: 2, team: 'red', strength: 2, ability: 3, day: 1 },
{ Level: 2, team: 'silver', strength: 2, ability: 3, day: 1 },
{ Level: 2, team: 'red', strength: 2, ability: 3, day: 2 },
{ Level: 2, team: 'silver', strength: 2, ability: 3, day: 2 },
{ Level: 2, team: 'red', strength: 2, ability: 4, day: 1 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 1 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 2 },
{ Level: 3, team: 'red', strength: 3, ability: 4, day: 3 }
];
const _groupPlayersByTeamAndDay = (players=[]) =>
players.reduce((acc,item) => {
const { team, day } = item;
const key = `${team}${day}`;
const prev = acc[key];
if(!prev) acc[key] = [item];
else acc[key].push(item);
return acc;
}, {});
const _getLowestValueOfAttr = (list=[], attr) =>
list.reduce((acc,item) =>
item[attr] < acc ? item[attr] : acc, Number.MAX_VALUE);
const _countItemsWithKeyValuePairs = (list=[], keys=[], values=[]) =>
list.reduce((acc,item) =>
keys.every((key,i) => item[key]===values[i]) ? acc+1 : acc, 0);
const _matchesFilterConditions = (filterConditions={}, player={}) =>
Object.entries(filterConditions).every(([key,value]) => player[key]===value);
const _filterArrHelper = (teamDayPlayersMap={}) =>
Object.values(teamDayPlayersMap).map(teamDayPlayersList => {
let list = [...teamDayPlayersList];
if(list.length <= 1) return list;
let filterConditions = {};
const lowestLevel = _getLowestValueOfAttr(list, 'Level');
const playersWithLowestLevel = _countItemsWithKeyValuePairs(list, ['Level'], [lowestLevel]);
if(playersWithLowestLevel <= 1) {
//remove the player with lowest Level
filterConditions = { Level: lowestLevel };
} else {
const lowestStrength = _getLowestValueOfAttr(list, 'strength');
const playersWithLowestStrength = _countItemsWithKeyValuePairs(list, ['Level','strength'], [playersWithLowestLevel,lowestStrength]);
if(playersWithLowestStrength <= 1){
//remove the player with lowest strength
filterConditions = { Level: lowestLevel, strength: lowestStrength };
} else {
//remove the players with the lowest ability
const lowestAbility = _getLowestValueOfAttr(list, 'ability');
filterConditions = { Level: lowestLevel, strength: lowestStrength, ability: lowestAbility };
}
}
return list.filter(player =>
!_matchesFilterConditions(filterConditions, player));
}).flat();
const filterArr = (players=[]) => {
const teamDayPlayersMap = _groupPlayersByTeamAndDay(players);
return _filterArrHelper(teamDayPlayersMap);
}
console.log( filterArr(players) );
My code seems to be right, but it isn't returning a ':' but a ',' at certain places of the Json result. please see desired result in the code comments.
I also don't like the "replaces" I coded to remove the array's brackets from the Json expression and I shouldn't modify the JSON string. Is there a more elegant way to do it?
// JSON Object
var items = [
{
name: "item 1",
id: 2,
props: {
a: "a prop1",
b: "b prop1",
},
values: [1, 2, 3],
},
{
name: "item 2",
id: 3,
props: {
a: "a prop2",
b: "b prop2",
},
values: [6, 1, 2, 3, 4],
},
{
name: "item 3",
id: 4,
props: {
a: "a prop3",
c: "c prop3",
},
values: [10, 1, 2, 3, 4, 5],
},
];
export function getObject(items) {
var arr = [];
for(var i in items){
arr.push(items[i].name);
arr.push(items[i].props);
}
var myJSON = JSON.stringify(arr).toString();
var test = myJSON.replace("[","{").replace("]","}"); // I couldn't find another way to extract the array data from the array brackets.
var test2 = JSON.stringify(test);
// test2 is returning: "{\"item 1\",{\"a\":\"a prop1\",\"b\":\"b prop1\"},\"item 2\",{\"a\":\"a prop2\",\"b\":\"b prop2\"},\"item 3\",{\"a\":\"a prop3\",\"c\":\"c prop3\"}}"
// but it's expected: "{\"item 1\":{\"a\":\"a prop1\",\"b\":\"b prop1\"},\"item 2\":{\"a\":\"a prop2\",\"b\":\"b prop2\"},\"item 3\":{\"a\":\"a prop3\",\"c\":\"c prop3\"}}"
return test2;
}
Use .map to transform each item into an object, which has one property, whose key is the item.name, and value is the item.props object:
const getObject = items => items.map(item => ({ [item.name]: item.props }));
// JSON Object
var items = [{
name: "item 1",
id: 2,
props: {
a: "a prop1",
b: "b prop1",
},
values: [1, 2, 3],
},
{
name: "item 2",
id: 3,
props: {
a: "a prop2",
b: "b prop2",
},
values: [6, 1, 2, 3, 4],
},
{
name: "item 3",
id: 4,
props: {
a: "a prop3",
c: "c prop3",
},
values: [10, 1, 2, 3, 4, 5],
},
];
console.log(getObject(items));
If you actually need a JSON string and not an object, then put JSON.stringify around it. (remember: There's no such thing as a "JSON Object".)
const getObject = items => JSON.stringify(items.map(item => ({ [item.name]: item.props })));
// JSON Object
var items = [{
name: "item 1",
id: 2,
props: {
a: "a prop1",
b: "b prop1",
},
values: [1, 2, 3],
},
{
name: "item 2",
id: 3,
props: {
a: "a prop2",
b: "b prop2",
},
values: [6, 1, 2, 3, 4],
},
{
name: "item 3",
id: 4,
props: {
a: "a prop3",
c: "c prop3",
},
values: [10, 1, 2, 3, 4, 5],
},
];
console.log(getObject(items));
I have an object which has objects inside in it at the following form:
Object {
"item1": { "subitem1": 5, "subitem2": 10 },
"item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 },
"item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 }
}
I want to convert it to an array with the following form:
[0] Object { key: "item1", "subitem1": 5, "subitem2": 10 }
[1] Object { key: "item2", "subitem1": 3, "subitem2": 12, "subitem3": 1 }
[2] Object { key: "item3", "subitem1": 8, "subitem2": 1, "subitem3": 3 }
Any ideas? Thanks in advance
You could get the entries of the object and assign the key.
var object = { item1: { subitem1: 5, subitem2: 10 }, item2: { subitem1: 3, subitem2: 12, subitem3: 1 }, item3: { subitem1: 8, subitem2: 1, subitem3: 3 } },
result = Object.entries(object).map(([key, o]) => Object.assign({ key }, o));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Object.keys() and Array.prototype.map():
const obj = { "item1": { "subitem1": 5, "subitem2": 10 }, "item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 }, "item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 }},
res = Object.keys(obj).map(key => ({key, ...obj[key]}));
console.log(res);
Do note, however, the order of the keys retrieved from Object.keys is not guaranteed to be the same order as listed in your object
You can try this mate
let obj = { "item1": { "subitem1": 5, "subitem2": 10 }, "item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 }, "item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 } };
let op =[];
for(let key in obj){
op.push({
key : key,
...obj[key]
})
}
console.log(op);
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>