Devide player into two team by their ratings in angularjs / Javascript - javascript

I have an array of players with player name and ratings.
$scope.players = [
{"name": "Qasim", "rating": "10"},
{"name": "Mahsam", "rating": 10},
{"name": "Aj", "rating": 3},
{"name": "Osman", "rating": 7},
{"name": "Usama", "rating": 7},
{"name": "Bilal", "rating": 3}
]
I need to divide players into two team based on their ratings.
var playerLength = $scope.players.length,
grouped = _.groupBy($scope.players,function(item){return item.rating});
I want to divide players in two team with equal ratting in two balanced teams.

Here is a way to make your teams. I loop over all the players and push the player in the weakest team.
Here is a JSFiddle demo, more readable than the snippet.
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope', function($scope) {
$scope.players = [{
"name": "Qasim",
"rating": 10
}, {
"name": "Mahsam",
"rating": 10
}, {
"name": "Aj",
"rating": 3
}, {
"name": "Osman",
"rating": 7
}, {
"name": "Usama",
"rating": 7
}, {
"name": "Bilal",
"rating": 3
}];
$scope.team1 = [];
$scope.team2 = [];
$scope.createTeams = function() {
angular.forEach($scope.players, function(player) {
if ($scope.teamStrength($scope.team1) < $scope.teamStrength($scope.team2)) {
$scope.team1.push(player);
} else {
$scope.team2.push(player);
}
});
}
$scope.teamStrength = function(team) {
var sum = 0;
if(team.length == 0) return 0;
for(var i = 0; i < team.length; i++) {
sum += team[i].rating;
}
return sum;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<button ng-click="createTeams()">Create teams!</button>
<h1>Team 1</h1>
<div ng-repeat="p in team1">
{{p.name}} ({{p.rating}})
</div>
<h1>Team 2</h1>
<div ng-repeat="p in team2">
{{p.name}} ({{p.rating}})
</div>
</div>
</div>

var playerArr = {};
var rateArr = []
var leftTeam = [];
var rightTeam = [];
for(id in $scope.players){
playerArr[$scope.players[id].rating] = $scope.players[id];
rateArr.push($scope.players[id].rating);
}
rateArr.sort();
for(i = 0; i < rateArr.length; i+=2) {
leftTeam.push({name:playerArr[rateArr[id]].name, rating: playerArr[rateArr[id]].rating});
}
for(i = 1; i<rateArr.length; i+=2){
rightTeam.push({name.playerArr[rateArr[id]].name, rating: playerArr[rateArr[id]].rating;
}

A way to do it:
UPDATE: Change has been made to match the question.
var footballers = [
{"name": "Qasim", "rating": "10"},
{"name": "Mahsam", "rating": 10},
{"name": "Aj", "rating": 3},
{"name": "Osman", "rating": 7},
{"name": "Usama", "rating": 7},
{"name": "Bilal", "rating": 3}
];
footballers.sort(function(a, b){
return a.rating - b.rating
});
console.log(footballers); //sorted
var team1 = [], team2 = [];
//Assuming, footballers have the same rating twice
for (let index=0;index<footballers.length;index += 2) {
team1.push(footballers[index]);
team2.push(footballers[index+1]);
}
console.log(team1, team2);
:)

Related

Compare two arrays having objects and remove duplicates from first array

I have two arrays that contain objects. From first array how can I remove the items that are already present in the second array?
First array:
var s = [
{"Name": "1"},
{"Name": "2"},
{"Name": "3"},
{"Name": "4"},
{"Name": "5"},
{"Name": "6"}
]
Second array:
var t = [
{"Name": "1"},
{"Name": "2"},
{"Name": "3"},
{"Name": "8"}
]
Expected output:
[
{"Name": "4"},
{"Name": "5"},
{"Name": "6"}
]
You can use filter() along with some()
var s = [{"Name":"1"},{"Name":"2"},{"Name":"3"},{"Name":"4"},{"Name":"5"},{"Name":"6"}];
var t = [{"Name":"1"},{"Name":"2"},{"Name":"3"},{"Name":"8"}];
result = s.filter(a => !t.some(b => a.Name === b.Name));
console.log(result);
An approach using set and .filter method
var s=[
{
"Name": "1"
},
{
"Name": "2"
},
{
"Name": "3"
},
{
"Name": "4"
},
{
"Name": "5"
},
{
"Name": "6"
}
];
var t= [
{
"Name": "1"
},
{
"Name": "2"
},
{
"Name": "3"
},{
"Name": "8"
}
];
var set = new Set();
t.forEach(obj => set.add(obj.Name));
s=s.filter(obj => !set.has(obj.Name))
console.log(s);
z = f(s, t);
function f(first, second) {
var z = [];
for (var i = 0; i < first.length; i++) {
var included = false;
for (let j = 0; j < second.length; j++) {
if(equal(first[i], second[j]))
included = true;
//break; //optional
}
if(!included)
z.push(first[i]);
}
return z;
}
function equal(a,b){
//however you define the objs to be equal
return a.Name == b.Name;
}

Remove empty string in nested json object via AngularJS

I have an nested json object in which I need to remove empty values and create new json which should contain only data objects.
json file:
myData = [{
"id": 1,
"values": [{
"value": ""
}]
}, {
"id": 2,
"values": [{
"value": 213
}]
}, {
"id": 3,
"values": [{
"value": ""
}, {
"value": ""
}, {
"value": "abc"
}]
},{
"id": 4,
"values": [{
"value": ""
}]
},{
"id": 33,
"values": [{
"value": "d"
}]
}];
Output should be:
myNewData = [{
"id": 2,
"values": [{
"value": 213
}]
}, {
"id": 3,
"values": [{
"value": "abc"
}]
},{
"id": 33,
"values": [{
"value": "d"
}]
}];
So far I have created this:
angular.module('myapp',[])
.controller('test',function($scope){
$scope.myData = [{
"id": 1,
"values": [{
"value": ""
}]
}, {
"id": 2,
"values": [{
"value": 213
}]
}, {
"id": 3,
"values": [{
"value": ""
}, {
"value": ""
}, {
"value": "abc"
}]
},{
"id": 4,
"values": [{
"value": ""
}]
},{
"id": 33,
"values": [{
"value": "d"
}]
}];
})
.filter('filterData',function(){
return function(data) {
var dataToBePushed = [];
data.forEach(function(resultData){
if(resultData.values && resultData.values != "")
dataToBePushed.push(resultData);
});
return dataToBePushed;
}
});
Html:
<div ng-app="myapp">
<div ng-controller="test">
<div ng-repeat="data in myData | filterData">
Id:{{ data.id }}
</br>
Values: {{ data.values }}
</div>
</div>
</div>
I am not able to access and remove value inside values object. Right now i am simply showing the data using ng-repeat but i need to create a new json file for that.
You work with the array in your AngularJS Controller doing Array.prototype.map() and Array.prototype.filter(). Map all objects doing a filter to exclude the items with empty values item.values.value, and than a filter to get the array elements that have values with value:
var myData = [{"id": 1,"values": [{ "value": ""}]}, {"id": 2,"values": [{"value": 213}]}, {"id": 3,"values": [{"value": ""}, {"value": ""}, {"value": "abc"}]}, {"id": 4,"values": [{"value": ""}]}, {"id": 33,"values": [{"value": "d"}]}],
myDataFiltered = myData
.map(function (item) {
item.values = item.values.filter(function (itemValue) {
return itemValue.value;
});
return item;
})
.filter(function (item) {
return item.values.length;
});
console.log(myDataFiltered);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6:
myDataFiltered = myData
.map(item => {
item.values = item.values.filter(itemValue => itemValue.value);
return item;
})
.filter(item => item.values.length);
Here you go with a multiple for-loop.
myData = [{
"id": 1,
"values": [{
"value": ""
}]
}, {
"id": 2,
"values": [{
"value": 213
}]
}, {
"id": 3,
"values": [{
"value": ""
}, {
"value": ""
}, {
"value": "abc"
}]
},{
"id": 4,
"values": [{
"value": ""
}]
},{
"id": 33,
"values": [{
"value": "d"
}]
}];
function clone(obj){ return JSON.parse(JSON.stringify(obj));}
var result = [];
for(var i = 0; i < myData.length; i++){
var current = clone(myData[i]);
for(var j = 0; j < current.values.length; j++){
if(current.values[j].value == null || current.values[j].value == ""){
current.values.splice(j, 1);
j--;
}
}
if(current.values.length > 0) result.push(current);
}
console.log(myData);
console.log(result);
If you want to delete them completely, you can iterate over the array like this;
angular.forEach($scope.myData, function(data){
for(var i=0; i < data.values.length; i++){
if(data.values[i] !== ""){
break;
}
delete data;
}
});
The if statement checks all values in the array, and breaks if it's not equal to "", otherwise if all values are = "" it deletes the object.
Hope it helps!
Here's a recursive function to do the job.
This will only work if myData is an array and the value inside it or its children is a collection of object.
var myData = [{"id": 1, "values": [{"value": ""}] }, {"id": 2, "values": [{"value": 213 }] }, {"id": 3, "values": [{"value": ""}, {"value": ""}, {"value": "abc"}] },{"id": 4, "values": [{"value": ""}] },{"id": 6, "values": ""},{"id": 33, "values": [{"value": "d"}] }];
function removeEmptyValues (arr) {
var res = false;
/* Iterate the array */
for (var i = 0; i < arr.length; i++) {
/* Get the object reference in the array */
var obj = arr[i];
/* Iterate the object based on its key */
for (var key in obj) {
/* Ensure the object has the key or in the prototype chain */
if (obj.hasOwnProperty(key)) {
/* So, the object has the key. And we want to check if the object property has a value or not */
if (!obj[key]) {
/*
If it has no value (null, undefined, or empty string) in the property, then remove the whole object,
And reduce `i` by 1, to do the re-checking
*/
arr.splice(i--, 1);
/* Amd set whether the removal occurance by setting it to res (result), which we will use for the next recursive function */
res = true;
/* And get out from the loop */
break;
}
/* So, the object has a value. Let's check whether it's an array or not */
if (Array.isArray(obj[key])) {
/* Kay.. it's an array. Let's see if it has anything in it */
if (!obj[key].length) {
/* There's nothing in it !! Remove the whole object again */
arr.splice(i--, 1);
/* Amd set whether the removal occurance by setting it to res (result), which we will use for the next recursive function */
res = true;
/* Yes.. gets out of the loop */
break;
}
/*
Now this is where `res` is being used.
If there's something removed, we want to re-do the checking of the whole object
*/
if ( removeEmptyValues(obj[key]) ) {
/* Something has been removed, re-do the checking */
i--;
}
}
}
}
}
return res;
}
removeEmptyValues (myData);
Try this:
var myData = [{"id": 1,"values": [{ "value": ""}]}, {"id": 2,"values": [{"value": 213}]}, {"id": 3,"values": [{"value": ""}, {"value": ""}, {"value": "abc"}]}, {"id": 4,"values": [{"value": ""}]}, {"id": 33,"values": [{"value": "d"}]}]
let result=[],p=[];
myData.filter(el => {
p=[];
el.values.filter(k => {k.value != '' ? p.push({value : k.value}) : null});
if(p.length) result.push({id : el.id, values : p})
})
console.log('result', result);
You are going to right way but need some more operation like this :
angular.module('myapp',[])
.controller('test',function($scope){
$scope.myData = [{
"id": 1,
"values": [{
"value": ""
}]
}, {
"id": 2,
"values": [{
"value": 213
}]
}, {
"id": 3,
"values": [{
"value": ""
}, {
"value": ""
}, {
"value": "abc"
}]
},{
"id": 4,
"values": [{
"value": ""
}]
},{
"id": 33,
"values": [{
"value": "d"
}]
}];
})
.filter('filterData',function($filter){
return function(data) {
var dataToBePushed = [];
data.forEach(function(resultData){
var newValues=resultData;
var hasData=$filter('filter')(resultData.values,{value:'!'},true);
if(resultData.values && resultData.values.length>0 && hasData.length>0){
newValues.values=hasData;
dataToBePushed.push(newValues);
}
});
debugger;
return dataToBePushed;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<div ng-controller="test">
<div ng-repeat="data in myData | filterData:''">
Id:{{ data.id }}
</br>
Values: {{ data.values }}
</div>
</div>
</div>

Group and summarize json data to new json object

I am using angularJS and have a JSON object from an API response which looks like the following:
var data = [
{"group": "red", "state": "running"},
{"group": "red", "state": "closed"},
{"group": "red", "state": "closed"},
{"group": "blue", "state": "running"},
{"group": "blue", "state": "running"}
];
I would like to parse this object inside a javascript function to get the following result:
var sumdata = [
{"group": "red", "running": 1, "closed": 2, "summary": 3},
{"group": "blue", "running": 2, "closed": 0, "summary": 2}
];
So, I have to group the first property called "group", then count how many objects in this group are in running state, closed state and also summarize the count of objects.
(Note:
I would not like to use extra javascript libraries like LINQ.js
)
Could yo help me please?
I tried the following, which is missing the group by and have no idea how to put that into this function:
var getSum = function (data) {
if (!data) {
$scope.data = [];
}
else {
for (var i = 0; i < data.length; i++) {
var group = data[i][0];
var status = data[i][1];
status = (status ? status.Name : "").toUpperCase();
var running = 0;
var closed = 0;
switch (status) {
case "RUNNING":
running++;
break;
case "CLOSED":
closed++;
break;
default:
break;
}
var summary = running + closed;
$scope.dataSum.push({ "group": group, "running": running, "closed": closed, "summary": summary});
}
}
};
This is a proposal with a temporary object and an Array#forEach loop in plain Javascript.
var data = [{ "group": "red", "state": "running" }, { "group": "red", "state": "closed" }, { "group": "red", "state": "closed" }, { "group": "blue", "state": "running" }, { "group": "blue", "state": "running" }],
grouped = function (array) {
var r = [];
array.forEach(function (a) {
if (!this[a.group]) {
this[a.group] = { group: a.group, running: 0, closed: 0, summary: 0 };
r.push(this[a.group]);
}
this[a.group][a.state]++;
this[a.group].summary++;
}, Object.create(null));
return r;
}(data);
document.write('<pre>' + JSON.stringify(grouped, 0, 4) + '</pre>');
With the LINQ power it will look something like that:
var data = [{
"group": "red",
"state": "running"
}, {
"group": "red",
"state": "closed"
}, {
"group": "red",
"state": "closed"
}, {
"group": "blue",
"state": "running"
}, {
"group": "blue",
"state": "running"
}];
var result = Enumerable.From(data).GroupBy('$.group', null, function(key, group) {
return {
group: key,
running: group.Where(function(value) {
return value.state == 'running'
}).Count(),
closed: group.Where(function(value) {
return value.state == 'closed'
}).Count(),
summary: group.Where(function(value) {
return value.state == 'running' || value.state == 'closed'
}).Count()
}
}).ToArray()
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
The below snipped works for any number of fields in the data array. You only give the name of the field you want to group by. it is better than other examples in the way that it will work for any kind of data not only named like you suggested.
Hope it help.
(function(){
var data = [
{ "group": "red", "state": "running" },
{ "group": "red", "state": "closed" },
{ "group": "red", "state": "closed" },
{ "group": "blue", "state": "running" },
{ "group": "blue", "state": "running" },
{ "group": "blue", "state": "asd", "value":"33" },
{ "group": "blue", "state": "asd1", "value":"33" },
{ "group": "red", "state": "asd", "value":"33" }
],
grouped = function (array) {
var r = [];
var groupFieldName = "group";
array.forEach(function (a) {
var self = this;
if (!self[a[groupFieldName]]) {
var tempObj = {
group: a[groupFieldName]
};
self[a[groupFieldName]] = tempObj;
r.push(self[a[groupFieldName]]);
}
var keys = Object.keys(a);
keys.forEach(function(key){
if(key != groupFieldName){
if(self[a[groupFieldName]][a[key]] == undefined){
self[a[groupFieldName]][a[key]] = 1;
}else{
self[a[groupFieldName]][a[key]]++;
}
}
});
}, Object.create(null));
return r;
}(data);
console.log(JSON.stringify(grouped));
})()

Jquery substring/split

$("#ELEMENT").TEXT() is giving me and html string.
<div id="ELEMENT">
{
"products": [
{
"TPNB": "52260983",
"name": "name1",
"price": 0.89,
"quantity": 1
},
{
"TPNB": "73559869",
"name": "name2",
"price": 1.1,
"quantity": 1
},
{
"TPNB": "51447540",
"name": "Tesco Dijon Mustard 185g",
"price": 0.55,
"quantity": 1
},
{
"TPNB": "61227739",
"name": "name3150ml",
"price": 0.6,
"quantity": 1
},
{
"TPNB": "56925638",
"name": "Tesco Chicken Thighs 1kg",
"price": 2.5,
"quantity": 2
}
]
}
</div>
I want to extract this Array into following index
"TPNB":"52260983","name":"name1","price":0.89,"quantity":1
"TPNB":"52260983","name":"name2","price":0.89,"quantity":1
"TPNB":"56925638","name":"name13","price":2.5,"quantity":2
var parsedJson = JSON.parse($("#ELEMENT").text())
var finalArray = new Array()
for (var i in parsedJson.products)
{
finalArray.push(parsedJson.products[i]);
}
for (var i in finalArray)
{
console.log(JSON.stringify(finalArray[i]).replace("{", "").replace("}", ""))
}
after this you can access properties as such
finalArray[0].TPNB
finalArray[0].name
finalArray[0].price
finalArray[0].quantity
for the full code open you browser console and check out this http://jsfiddle.net/5wd29qch/1/
If the text is a valid json, you can parse it and get the products property which is the array you want:
var raw = $("#ELEMENT").text(),
parsed = JSON.parse(raw),
products = parsed.products;
console.log(products);
console.log(products[0]);
console.log(products[1]);
console.log(products[2]);
var jsonData = // ur data from .text()
var productData = JSON.parse(jsonData);
var productRows = productData.products;
for(var i = 0; i < productRows.length; i++)
{
alert(productRows[i]);
}
Try this:
var json = $.parseJSON($('#ELEMENT').text());
json.products.map(function(v, i){
console.log(JSON.stringify(v).replace('{','').replace('}',''));
});
Output:
"TPNB":"52260983","name":"name1","price":0.89,"quantity":1
"TPNB":"73559869","name":"name2","price":1.1,"quantity":1
"TPNB":"51447540","name":"Tesco Dijon Mustard 185g","price":0.55,"quantity":1
"TPNB":"61227739","name":"name3150ml","price":0.6,"quantity":1
"TPNB":"56925638","name":"Tesco Chicken Thighs 1kg","price":2.5,"quantity":2

Converting into a hierarchical array in javascript

Fiddle Example
I want to convert this JSON data
var data = [
{
"computer": 24,
"brand": "Italy A",
"phone": 0,
"country": "Italy"
},
{
"brand": "Italy C",
"computer": 0,
"phone": 0,
"country": "Italy"
},
{
"brand": "Brazil B",
"computer": 0,
"phone": 22,
"country": "Brazil"
},
{
"computer": 0,
"brand": "Brazil D",
"phone": 62,
"country": "Brazil"
},
{
"computer": 34,
"brand": "US E",
"phone": 41,
"country": "US"
}
];
into a hierarchical form for a d3 graph:
{
"name": "categories",
"children": [
{
"name": "phone",
"children": [
{
"name": "US",
"children": [
{
"brand": "US E",
"size": 41
}
]
},
{
"name": "Brazil",
"children": [
{
"brand": "Brazil B",
"size": 22
},
{
"brand": "Brazil D",
"size": 62
}
]
},
{
"name": "Italy",
"children": []
}
]
},
{
"name": "computer",
"children": [
{
"name": "US",
"children": [
{
"brand": "US E",
"size": 34
}
]
},
{
"name": "Brazil",
"children": []
},
{
"name": "Italy",
"children": [
{
"brand": "Italy A",
"size": 24
}
]
}
]
}
]
}
I came up with this code to generate the format:
function group_children(data){
var categories = ["phone","computer"];
var countries = ["US","Brazil","Italy"];
var object = {name:"categories",children:[]};
for(var c =0; c < categories.length;c++){
object.children.push({"name":categories[c],children:[]});
for(var con = 0;con < countries.length;con++){
object.children[c].children.push({"name":countries[con],"children":[]});
}
}
for(var i = 0;i < data.length;i++){
var row = data[i];
for(var c =0; c < categories.length;c++){
for(var con = 0;con < countries.length;con++){
var cat_key = categories[c],
country_key = countries[con];
if(row[cat_key] > 0){
if(object.children[c].name == cat_key && row.country == country_key){ object.children[c].children[con].children.push({brand:row["brand"],size:row[cat_key]});
}
}
}
}
}
return object;
}
Is it possible , during the iteration, not to push a country into the brand or computer's children array if the country's children array is empty?
For example, these objects should be removed
// computer
{
"name": "Brazil",
"children": []
}
// phone:
{
"name": "Italy",
"children": []
}
Here's the part that push each country into each category's children array:
for(var c =0; c < categories.length;c++){
object.children.push({"name":categories[c],children:[]});
for(var con = 0;con < countries.length;con++){
object.children[c].children.push({"name":countries[con],"children":[]});
}
}
My approach is probably wrong, so any other suggestions converting the data into that hierarchical form is also appreciated.
Check this fiddle, is this what you're looking for? I decided to go for a different approach to the one you followed, hope you don't mind. I've commented the code so that it's clearer:
var result = {
name: "categories",
children: [{
"name": "phone",
"children": []
}, {
"name": "computer",
"children": []
}]
};
$.each(data, function (index, item) {// Go through data and populate the result object.
if (+item.computer > 0) { // Computer has items.
filterAndAdd(item, result.children[1], "computer");
}
if (+item.phone > 0) { // Phone has items.
filterAndAdd(item, result.children[0], "phone");
}
});
function filterAndAdd(item, result_place, type) {// Search and populate.
var i = -1;
$.each(result_place.children, function (index,a) {
if( a.name === item.country ) {
i = index;
return false;
}
});
if (i > -1) {// Country already exists, add to children array.
result_place.children[i].children.push({
"brand": item.brand,
"size": item[type]
});
} else {// Country doesn't exist, create it.
result_place.children.push({
"name": item.country,
"children": [{
"brand": item.brand,
"size": item[type]
}]
});
}
}
Hope it helps.
You have to use d3.nest() function to group array elements hierarchically. The documentation is available
here. Also go through this tutorial which could definitely help you to create hierarchical data.
That's not enough, you get hierarchical data in terms of key and value pairs. But if you want to convert into name and children, already a question on SO is asked, check this.
With your current approach you should iterate the data to find the empty ones, before pushing the countries, which would result in way more iteration than just simply iterating the result at the end to filter the empty ones.
Otherwise you should create the scruture in the same iterations of the data insertion, thus reducing the iterations to 1.

Categories