What kind of query creates an olympic ranking (gold > silver > brass)? - c#

I want to make an olympic medal ranking.
Right now I have a pivot table that has a CountryID, MatchID and Medal column.
The medal column stores the values 1 (gold), 2 (silver) and three (brass).
Countries with the most gold should be the heighest in the rank, followed by the most silver etc. Only thing is, when gold is equal then the amount of silver medals should be taken in account and ofcourse if that is also equal compare brass medals.
Right now I take the following (not successful) approach:
First I make 3 queries like this to get an overview of the amount of medals per country:
var resGold = context.olympics_landen_wedstrijd.Where(n => n.medal == 1).GroupBy(n => n.LandID).Select(g => new { g.Key, Count = g.Count(), Medal = 2 }).OrderByDescending(n => n.Count);
Then I combine resGold, resSilver and resBrass into one list. That list I query again to get a ranking where countries with the most gold are ranked higher.
var list = all.OrderBy(t => t.Medal == 1 ? 1 : (t.Medal == 2 ? 2 : t.Medal == 3 ? 3 : 4)).ToList();
The problem is that I end up with a list where countries are ranked more then once. When Germany and the USA both have 10 golden medals and they both also have silver medals then there is another record for both countries in the list.
How can I achieve to get a ranking according to olympic standards with my database setup?
The result I'm looking to create is:
[RANK 1] CountryID = 2, numberofGold = 10, numberofSilver = 3, numberOfBrass = 5
[RANK 2] CountryID = 3, numberofGold = 10, numberofSilver = 9, numberOfBrass = 9
[RANK 3] CountryID = 4, numberofGold = 9, numberofSilver = 10, numberOfBrass = 10
....
Thanks in advance!

You can compute score for every country based in Weighted Rank.
The ratio can be gold:silver:bronz = 5:3:1
you can sort country based on score Desc
Review
Olympic medal table

Related

Create sub array of duplicates and randomize order c#

I am returning a list of items from the Database. List contains info like id, first name, last name, # of sales, $ revenue.
1 John James 431 213000
2 Scott Smith 301 43000
3 Jane Doe 431 300000
4 Tess Jones 431 14280
my results will contain the 4 rows as shown above. I am ordering my rows in descending order based on the # sales value. If the # sales value is the same then I order by id. So after ordering my results will look like so:
3 Jane Doe 431 300000
1 John James 431 213000
4 Tess Jones 431 14280
2 Scott Smith 301 43000
Now I would like to randomize the order of the rows where the #sales are the same. I am sure that means that I probably won't use the order by id.
How can I create a subarray of my results where the #sales are the same and then randomize their order and insert it to the original array? The main reason I am doing this is to add some variety to the data I will display so it not the same and gives the users the opportunity to be displayed in a different order.
This is how i am getting my original data:
results = results.OrderByDescending(x => Math.Max((uint)x.TotalSales, x.TotalRevenue))
.GroupBy(x => x.Id)
.Select(x => x.First()).ToList();
I believe I will be applying the randomizing part as follows:
var randomIndx= new Random(TotalSales).Next(100) % (#: will this be the number of duplicates?);
so that
I am not sure how to put things together. Any helpful tips are much appreciated.
Apply an ordering to your collection using Random, which will shuffle the results. Using ThenBy will ensure that entries are shuffled only within their previous-level ordering (items will be shuffled within their same "NumOfSales").
For example, with class:
public class Employee
{
public int Id{get;set;}
public string Name{get;set;}
public int NumOfSales{get;set;}
public int Revenue{get;set;}
}
Your code could look like this:
var originalEmployeeList = new List<Employee>()
{
new Employee { Id = 1, Name = "John James", NumOfSales = 431, Revenue = 213000 },
new Employee { Id = 2, Name = "Scott Smith", NumOfSales = 301, Revenue = 43000 },
new Employee { Id = 3, Name = "Jane Doe", NumOfSales = 431, Revenue = 300000 },
new Employee { Id = 4, Name = "Tess Jones", NumOfSales = 431, Revenue = 14280 },
};
var random = new Random();
var randomizedResults = originalEmployeeList
.OrderByDescending(x => x.NumOfSales)
.ThenBy(x => random.Next())
.ToList();
The key here is using random.Next() INSIDE a ThenBy. With this example, people with a NumOfSales = 431 will always appear before people with a NumOfSales = 301, but the listing of people within the same NumOfSales will be randomized.
Here's a runnable example: https://dotnetfiddle.net/W2ESGt

unable to draw chart of highest sold products

I have a soldproduct table I want to draw the chart of the top 10 highest sold products.
trying it with following code but I don't know what is the exact problem while, it is logically right.
here is the error
System.ArgumentException: 'DbExpressionBinding requires an input expression with a collection ResultType. Parameter name: input'
DateTime start = startDate.Value;
DateTime end = EndDate.Value;
var TopTen = (from q in db.soldProduct
where (q.addDate >= start && q.addDate <= end)
orderby q.Barcode.Count() descending
select new
{
count = q.Barcode.Count(),
q.productName
}).Take(10);
foreach (var item in TopTen)
{
chartCustomer.Series["Customer"].Points.AddXY(item.productName, item.count);
}
ADDED :- I have in each row the item name and the quantity which might be one or more, I want to add that as well to the query but it is getting harder
model of the bill of soldProduct contains the following
public string barcode {get;set;}
public int productId{get;set;}
public string productName{get;set;}
public int quantity{get;set;}
public DateTime addDate{get;set;}
public double amount{get;set}
so the table if it has the following data
productId
barcode
productName
quantity
addDate
amount
1
111
milk
3
3/2/2020
15
1
111
milk
1
3/2/2020
5
2
222
bread
5
3/2/2020
20
3
333
cheese
1
3/2/2020
100
1
111
milk
3
3/2/2020
15
2
222
bread
3
3/2/2020
15
quantity of the of item sold the highest is bread with 8 occurrences it should come first then milk with 7 occurrences and then cheese.
Addition after comments: Apparently every SoldProduct has a property Amount. You don't want to count the number of SoldProducts, but the total Amount of all SoldProducts.
So if SoldProduct1 for product "Milk" has Amount 10 and SoldProduct[22] for product "Milk" has Amount 14, you want as result that of product "Milk" 24 items have been sold (= 10 + 14).
End addition after comment
So you have a table, SoldProducts. Every row in this table represents one Sale of a Product.
table SoldProducts has a.o. at least the following columns
AddDate: when was the sale
ProductName: the Name of the sold product,
Amount: the number of sold products in this sale.
I want ... the top 10 highest sold products
"highest sold products" probably doesn't have to do anything to do with the height of the sold products, but with the total Amount of products sold.
To calculate this, you need to make groups of SoldProducts with the same name. You'll get groups of the soldProducts with name: "Bread" and SoldProducts with name "Milk", etc.
Then you want to sum the total Amount of all soldProducts per group.
So if group "Bread" has 3 SoldProducts with Amounts 10, 7, 5, then you want as result: ["Bread", 22]. 22 is the total number of Breads sold.
You order the result of the grouping items by descending TotalAmount and take the first 10 items.
To group elements based on something common is done by one of the overloads of Enumerable.GroupBy. In this case, I take the overload with parameter resultSelector to count the number of elements in each group.
DateTime beginDate = ...
DateTime endDate = ...
var topTenSoldProductNames = dbContext.SoldProducts
.Where(soldProduct => beginDate <= soldProduct.AddDate
&& endDate >= soldProduct.AddDate)
// make groups with same ProductName
.GroupBy(soldProduct => soldProduct.ProductName,
// parameter resultSelector: take each ProductName,
// and all SoldProducts with this ProductName to make one new
(productName, soldProductsWithThisProductName) => new
{
Name = productName,
TotalAmount = soldProductsWithThisProductName
.Select(soldProduct => soldProduct.Amount)
.Sum(),
})
// order by descending TotalAmount, and take the first 10
.OrderByDescending(groupResult => groupResult.TotalAmount)
.Take(10);
Your query is wrong, you are returning count of chars. And without grouping this query is useless.
var groupingQuery =
from q in db.soldProduct
where (q.addDate >= start && q.addDate <= end)
group q by q.productName into g
select new
{
productName = g.Key,
count = g.Count(),
};
var TopTen = groupingQuery.OrderByDescending(x => x.count).Take(10);

Group by with a foreign key on single LINQ

I have 2 related tables and they are
Schedule
SlotId
Description
Amount
and Slot
Id
Name
Example data:
Schedule
slotid description amount
--------------------------------
1 Morning charge 300
1 Late fee 300
1 Earlier bonus 200
1 Half day 150
2 Morning charge 300
2 Late fee 300
2 Earlier bonus 200
2 Half day 150
3 Morning charge 300
3 Late fee 300
3 Earlier bonus 200
3 Half day 150
Final result wanted as a SlotSchedules list, like this:
SlotId
SlotName
List<Schedules>
I need:
fetched list of Schedules
and then find distinct slots in it
and then iterate through each slot and build the model i needed as below
This is what I tried with LINQ:
List<Schedules> schedulesAll = (from n in dbContext.Schedules
select n).ToList();
var slotsdistinct = schedulesAll.Select(x => x.SlotId).Distinct().ToList();
foreach (var slot in slotsdistinct)
{
var scheduledforslot = schedulesAll.Where(x => x.SlotId == slot).Select(x => x).ToList();
foreach (Schedules _schedule in scheduledforslot)
{
//ListModel.Add(new DetailsModel { Name = _schedule.Description, Amount = (_schedule.Amount });
}
}
Any way to make it in single LINQ query?
Try this:
var slotsSchedules = dbContext.Slots.ToList().Select(slot => new {
SlotID = slot.Id,
Name = slot.Name,
SlotSchedules = dbContext.Schedules.ToList()
.Where(schedule = > schedule.SlotId == slot.Id).ToList()});

Count Dates which a specific Customer does not have a Shop in it

Here is an example Data Table:
ID Amount Date
--------------------------
1 3.000 2016/1/1
2 4.000 2016/1/1
1 6.000 2017/1/1
1 3.000 2018/1/1
3 2.000 2019/1/1
I need to count Dates which a specific Customers does not have a Shop in it.
for example ID 2 does not have a shop in 2017/1/1 and 2018/1/1, so the count will be 2. and the count for customer ID 3 will be 3 because He does not have a shop in 2016/1/1 and 2017/1/1 and 2018/1/1
I think I should use grouping but do not know how to count which I want for a specific ID!
orders.GroupBy(x => x.Date)......???
Assuming you have list of objects:
// number of all different dates
var datesCount = list.Select(i => i.Date).Distinct().Count();
int customerId = 2;
//number of dates with customer shopping
var customerDatesCount = list.Where(i => i.ID == customerId).Select(i => i.Date).Distinct().Count();
var nonShoppingDatesCount = datesCount - customerDatesCount;
You need two steps here.
Get all distinct order dates
var allDates = orders.Select(o => o.Date).Distinct();
Find those dates which customer don't have. Except operation will do that
var missingDates = allDates.Except(orders.Where(o => o.ID == 2).Select(o => o.Date));
If you need just number of missing dates, then use missingDates.Count() or (better) use solution by #Roma

Filter C# Entity List

Hi to the helpfull community!
Guys I have a problem with a C# Entity/SQL Server 2014 project that gives me hard times
I have a procedure with this result set
OnDate RoomType Available RateCode Price
2016-12-12 DBL 2 BAR 200
2016-12-12 TRP 4 BAR 300
2016-12-12 DBL 2 NEW 250
2016-12-12 TRP 4 NEW 350
In my C# program I have a List that is fed from that procedure through the Entyity Framework
In order not to create another procedure and another LIST, is there a way, depending on my needs, to transform my List result within C# as follows?
OnDate RoomType Available RateCode Price
2016-12-12 DBL 2 0
2016-12-12 TRP 4 0
So it is basically the same result but DISTINCT with the RateCode empty and the Price = 0
I need both results sets for my processing. I do for loops and populate XMLs so when I need only RoomType-Availability if I am stuck with the first result I would get the same Room Types as many tmes as RateCodes exist which is not acceptable
for (int Row = 0; Row < myList.Count(); Row++)
{
blah
}
Thanx in advance!
This will return your desired list. You are grouping your collection by RoomType and Available and after that Select the data which you need.
var result = myList.GroupBy(x => new { x.RoomType, x.Available })
.Select(g => new Hotel {
OnDate = g.First().OnDate,
RoomType = g.Key.RoomType,
Available = g.Key.Available,
RateCode = "",
Price = 0 })
.ToList();
Here full code example: dotNetFiddle

Categories

Resources