Get Rank from list of object depending upon some condition - c#

I have list of object of class which contain totalScore as one property.I want to get rank of Team depending upon totalscore of team.Here is the list of object I called it as List data= new List();
so data contain object of scoreboard class with total score property.
I need rank of team depending upon totalscore.Here is the code that I try but it give result like Rank=1,2,2,3 but I need Rank=1,2,2,4 like this.
data.OrderByDescending(x => x.totalScore).GroupBy(x => x.totalScore)
.SelectMany((g, i) => g.Select(e => new { data = e.Rank = i + 1 }))
.ToList();
The data list contain unique team but there total score may be same so same totalscore team must be in one rank. please help me!

If you need to update the list in-place:
int i = 0;
decimal? prevValue = null;
foreach(var item in data.OrderByDescending(x => x.totalScore))
{
item.Rank = prevValue == item.totalScore ? i : ++i;
prevValue = item.totalScore;
}

A different notation (which I prefer for readability) but essentially the same answer as provided by user3185569.
var i = 1;
var results = (from d in data orderby d.totalScore descending select new { Obj = d, Rank = i++ } ).ToList();

Related

SQL to LINQ expres

I'm trying to convert a SQL expression to Linq but I can't make it work, does anyone help?
SELECT
COUNT(descricaoFamiliaNovo) as quantidades
FROM VeiculoComSeminovo
group by descricaoFamiliaNovo
I try this:
ViewBag.familiasCount = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo).Count();
I need to know how many times each value repeats, but this way it shows me how many distinct values ​​there are in the column.
You can try:
var list = from a in db.VeiculoComSeminovo
group a by a.descricaoFamiliaNovo into g
select new ViewBag{
familiasCount=g.Count()
};
or
var list = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo)
.Select (g => new ViewBag
{
familiasCount=g.Count()
});
If you need column value:
new ViewBag{
FieldName=g.Key,
familiasCount=g.Count()
};
You don't need the GROUP BY unless there are fields other than the one in COUNT. Try
SELECT
COUNT(descricaoFamiliaNovo) as quantidades
FROM VeiculoComSeminovo
UPDATE, from your comment:
SELECT
COUNT(descricaoFamiliaNovo) as quantidades,
descricaoFamiliaNovo
FROM VeiculoComSeminovo
GROUP BY descricaoFamiliaNovo
That's it as SQL. In LINQ it is something like:
var reponse = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo)
.Select ( n => new
{Name = n.key,
Count = n.Count()
}
)
Not tested.
Ty all for the help.
I solved the problem using this lines:
// get the objects on db
var list = db.VeiculoComSeminovo.ToList();
// lists to recive data
List<int> totaisFamilia = new List<int>();
List<int> totaisFamiliaComSN = new List<int>();
// loop to cycle through objects and add the values ​​I need to their lists
foreach (var item in ViewBag.familias)
{
totaisFamilia.Add(list.Count(a => a.descricaoFamiliaNovo == item && a.valorSeminovo == null));
totaisFamiliaComSN.Add(list.Count(a => a.descricaoFamiliaNovo == item && a.valorSeminovo != null));
}
The query was a little slow than I expected, but I got the data

Group and separate list

I have below entity structure
public class Item
{
public EnumType Type { get; set; }
public int Price { get; set; }
}
public enum EnumType
{
A =1,
B=2,
C =3
}
I have a list of items as follow
var items = new List<Item>
{
new Item{ Price=5, Type= EnumType.B},
new Item{ Price=5, Type= EnumType.B},
new Item{ Price=5, Type= EnumType.B},
new Item{ Price=10, Type= EnumType.B},
new Item{ Price=10, Type= EnumType.B},
new Item{ Price=10, Type= EnumType.B},
new Item{ Price=15, Type= EnumType.C},
new Item{ Price=15, Type= EnumType.C},
new Item{ Price=15, Type= EnumType.C},
new Item{ Price=15, Type= EnumType.C},
new Item{ Price=15, Type= EnumType.C}
};
If the price and type are same, based on type it need to exclude every nth item from the list and then calculate the sum.
i.e type B = 3, Type C = 4
Which means in above sample data, since there are 3 items each in type B once it group by price and type it need to exclude every 3rd item when calculate sum.
So sum for type B will be 5+5+10+10 and sum for type C will be 15+15+15+15
I tried using modular but seems its not the correct direction
I have tried this so far
static int GetFactorByType(EnumType t)
{
switch(t)
{
case EnumType.A:
return 2;
case EnumType.B:
return 3;
case EnumType.C:
return 4;
default:
return 2;
}
}
var grp = items.GroupBy(g => new { g.Type, g.Price }).Select(s => new
{
type= s.Key.Type,
price = s.Key.Price,
count = s.Count()
}).Where(d => d.count % GetFactorByType(d.type) == 0).ToList();
Here's one solve:
//track the type:nth element discard
var dict = new Dictionary<EnumType, int?>();
dict[EnumType.B] = 3;
dict[EnumType.C] = 4;
//groupby turns our list of items into two collections, depending on whether their type is b or c
var x = items.GroupBy(g => new { g.Type })
.Select(g => new //now project a new collection
{
g.Key.Type, //that has the type
SumPriceWithoutNthElement = //and a sum
//the sum is calculated by reducing the list based on index position: in where(v,i), the i is the index of the item.
//We drop every Nth one, N being determined by a dictioary lookup or 2 if the lookup is null
//we only want list items where (index%N != N-1) is true
g.Where((v, i) => (i % (dict[g.Key.Type]??2)) != ((dict[g.Key.Type] ?? 2) - 1))
.Sum(r => r.Price) //sum the price for the remaining
}
).ToList(); //tolist may not be necessary, i just wanted to look at it
It seemed to me like your question words and your example are not aligned. You said (and did in code):
If the price and type are same, based on type it need to exclude every nth item from the list and then calculate the sum. i.e type B = 3, Type C = 4
Which to me means you should group by Type and Price, so B/5 is one list, and B/10 is another list. But you then said:
Which means in above sample data, since there are 3 items each in type B once it group by price and type it need to exclude every 3rd item when calculate sum. So sum for type B will be 5+5+10+10
I couldn't quite understand this. To me there are 3 items in B/5, so B/5 should be a sum of 10 (B/5 + B/5 + excluded). There are 3 items in B/10, again, should be (B/10 + B/10 + excluded) for a total of 20.
The code above does not group by price. It outputs a collection of 2 items, Type=B,SumWithout=30 and Type=C,SumWithout=60. This one groups by price too, it outputs a 3 item collection:
var x = items.GroupBy(g => new { g.Type, g.Price })
.Select(g => new
{
g.Key.Type,
g.Key.Price,
SumPriceWithoutNthElement =
g.Where((v, i) => (i % (dict[g.Key.Type]??2)) != ((dict[g.Key.Type] ?? 2) - 1))
.Sum(r => r.Price) }
).ToList();
The items are Type=B,Price=5,SumWithout=10 and Type=B,Price=10,SumWithout=20 and Type=C,Price=15,SumWithout=60
Maybe you mean group by type&price, remove every 3rd item (from b, 4th item from c etc), then group again by type only and then sum
This means if your type B prices were
1,1,1,1,2,2,2,2,2
^ ^
we would remove one 1 and one 2 (the Ines with arrows under them), then sum for a total of 9. This is different to removing every 3rd for all type b:
1,1,1,1,2,2,2,2,2
^ ^ ^
?
In which case, maybe group by Type/sum again the SumWithout output from my second example
I did consider that there might be a more efficient ways to do this without LINQ.. and it would nearly certainly be easier to understand the code if if were non LINQ - LINQ isn't necessarily a wonderful magic bullet that can kill all ptoblems, and even though it might look like a hammer with which every problem can be beaten, sometimes it's good to avoid
Depending on how you intended the problem to be solved (is price part of the group key or not) building a dictionary and accumulating 0 instead of th price every Nth element might be one way.. The other way, if price is to be part of the key, could be to sum all the prices and then subtract (count/N)*price from the total price
Grouping by a new object, which is always unique, guarantees you that you'll have as many groups as you have items. Try something like this:
var grp = items.GroupBy(g => $"{g.Type}/{g.Price}").Select(s => new
{
type= s.Value.First().Type,
price = s.Value.First().Price,
count = s.Value.Count()
}).Where(d => count % GetFactorByType(d.type) == 0).ToList();
This way, you group by a string composed from the type/price combination, so if the items are equivalent, the strings will be equal.
The $"{g.Type}/{g.Price}"string amounts to "B/5" for your first three item examples, so it's quite readable as well.

Counting number of items in ObservableCollection where it equals 1 - C#

I made an SQL query and filled the data to an ObservableCollection. The database contains many columns so I want to count how many instances where a specific column = 1, then return that number to an int.
The query:
var test = from x in m_dcSQL_Connection.Testheaders
where dtStartTime <= x.StartTime && dtEndtime >= x.StartTime
select new {
x.N,
x.StartTime,
x.TestTime,
x.TestStatus,
x.Operator,
x.Login,
x.DUT_id,
x.Tester_id,
x.PrintID
};
Then I add the data pulled from the database to an Observable Collection via:
lstTestData.Add(new clsTestNrData(item.N.ToString(),
item.StartTime.ToString(),
item.TestTime.ToString()
etc.....
I want to count how many times TestStatus = 1.
I have read about the .Count property but I do not fully understand how it works on ObservableCollections.
Any help?
The standard ObservableCollection<T>.Count property will give you the number of items in the collection.
What you are looking for is this:
testStatusOneItemCount = lstTestData.Where(item => item.TestStatus == 1).Count()
...which uses IEnumerable<T>.Count() method which is part of LINQ.
To elaborate a bit, Count will simply count the objects in your collection.
I suggest having a quick look at linq 101. Very good examples.
Here's an example:
// Assuming you have :
var list = new List<int>{1,2,3,4,5,6 };
var items_in_list = list.Count(); // = 6;
Using linq's Where, you're basically filtering out items, creating a new list. So, the following will give you the count of all the numbers which are pair:
var pair = list.Where(item => item%2 ==0);
var pair_count = pair.Count; // = 3
You can combine this without the temp variables:
var total = Enumerable.Range(1,6).Where(x => x % 2 ==0).Count(); // total = 6;
Or you can then select something else:
var squares_of_pairs = Enumerable.Range(1,6)
.Where(x => x % 2 ==0).
.Select( pair => pair*pair);
// squares_of_pairs = {4,16, 36}. You can count them, but still get 3 :)

Best way to join / sort two lists

I am trying to figure out what would be the best / fastest way to accomplish next task.
There is a list of int:
{ 4, 1, 112, 78 }
and there is a list of objects:
object { Id, Date, Value }
Rules:
{int list} contains Ids which are not sorted in any particular order
{int list} contains unknown number of elements
{object list} will always have only one Id occurrence in one particular day. There can be not one date with two same Ids (the list of object is already supplied like this). You could say that Id+Date represents a unique object.
JOIN Part: one day could have 1...n items, where 'n' represents the number of elements in {int list}. Requirement is that in final result all days have 'n' Ids. So if the day 1/1/2014 does not have item with Id=42, then a new item will be added to this list with Value=0.
SORT part: {object list} needs to be sorted by date, and then by Id, but the Id order must be the same as it is in {int list}.
What would be the best algorithm to accomplish this task? This is what I do currently:
// first I insert all the missing Ids
// to achieve this, I sorted lists so I now when to expect which Id
var orderedIntList = intList.OrderBy(x => x).ToList();
var orderedObjectList = objectList.OrderBy(x => x.Date).ThenBy(x => x.Id).ToList();
for (int i = 0; i < totalRecords; i++)
{
currentIndex = i % 4;
currentId = orderedIntList[currentIndex];
if (orderedObjectList.Count <= i || currentId != orderedObjectList[i].Id)
orderedObjectList.Insert(i, new Object { Date = currentDate, Id = currentId });
currentDate = orderedList[i].Date;
}
// then in order to have items sorted in original order, I use LINQ join
int counter = 0;
var aListWithIndex = activityIds.Select(x => new { Index = counter++, Id = x }).ToList();
return (from a in aListWithIndex
join b in orderedObjectList on a.Id equals b.Id
orderby b.Date, a.Index
select b
)
.ToList();

Grouping duplicate items in a list, and adding their totals

Hello I have a list and I am trying to group duplicates and add their quantity to compare it to a max quantity number. The only problem I'm running into is isolating the duplicates and adding their quantities. I have come to a mental block and just can't figure out the right way to acheive what I am trying. So I was hoping that someone would be able to point me in the right direction and help get me unstuck!
The property that I am checking on for duplicates is the ProductID
double qty = 0;
double totalQty = 0;
bool isQtyValid = true;
List<ShoppingCartDTO> shoppingList = ShoppingCart.Fetch(string.Format("WHERE SessionID='{0}'", Session["ID"]));
foreach (ShoppingCartDTO temp in shoppingList)
{
qty = temp.Quantity;
totalQty += qty;
isQtyValid = getCheckQty(totalQty, temp.ProuductID, temp.CustomerID);
CheckOut.Enabled = isQtyValid;
lblError.Visible = !isQtyValid;
}
If more explaining can be done, I can try to explain better, as well as provide more code if needed. I appreciate anyone's advice and help. Thanks!
If I understood you correctly:
var groupedList = shoppingList.GroupBy( item => item.[the property you want to group by on]);
foreach (var g in groupedList)
{
var sum = g.Sum( i => i.[the property you want to sum]);
}
hope it helps
A.Intersect(B).Count;
would this be able to find out the duplicate item count?
You might also implement IEquatable interface for your ShoppingCartDTO class:
class ShoppingCartDTO : IEquatable<ShoppingCartDTO>
{
}
Old style solution, something like.
List<ShoppingCartDTO> shoppingList = ShoppingCart.Fetch(string.Format("WHERE SessionID='{0}'", Session["ID"]));
Dictionary<String, Double> groups = new Dictionary<String,Double>();
foreach (ShoppingCartDTO temp in shoppingList)
{
String key = String.Format("{0}-{1}", temp.CustomnerID, temp.ProductID);
if (groups.ContainsKey(key))
{
groups[key] += temp.Quantity;
}
else
{
groups.Add(key, temp.Quantity);
}
}
Assuming there's some property that defines your "duplicate" like ProductId:
var results = shoppingList.GroupBy(s => s.ProductID)
.Select(g => new {
ProductID = g.Key,
totalQty = g.Sum(I => i.Quantity)
}
);
You could do something like this:
var groups = shoppingList.GroupBy(e => e.ProductId).ToList();
shoppingList.Clear();
foreach (var group in groups)
{
group.First().Quantity = group.Sum(e => e.Quantity);
shoppingList.Add(group.First());
}
After this runs, shoppingList should contain no duplicates and the Quantity value will have been summed for all duplicates.

Categories

Resources