How to use group by on multiple columns with Max function - c#

Here is a sample table, in which I am going to extract the records with the highest priority, corresponding to each pair of ID and code, as below:
Here is my approach to hit the mark:
var max = from item in items
group item by new {item.code, item.id} into r
select new MyObjectType(r.Select(q => q.code),
r.Select(q => q.id),
r.Max(q => q.priority));
But the result is null...
Any idea to fix the problem?!
Edit:
Here is a brief example:
(code,id,priority)
(1,10,100)
(1,10,200)
(1,11,300)
(1,11,400)
(2,12,500)
(2,12,600)
(2,13,700)
(2,13,800)
And the result of the query should be:
(1,10,200)
(1,11,400)
(2,12,600)
(2,13,800)

Make public properties in class and do like this:
var max = from item in items
group item by new {item.code, item.id} into r
select new MyObjectType
{
Code = r.Key.code,
Id = r.Key.id,
MaxValue = r.Max(q => q.priority)
};
Your class should look like:
public class MyObjectType
{
public int Code { get; set; }
public int Id { get ; set; }
public int MaxValue { get; set; }
}

Related

Return List from multiple search in C#

I have TextBox where users can input many numbers (1 per line).
Then, I'm querying a Child Table which has those numbers.
Those numbers are ForeignKeys from Primary Table.
Primary Table - tblOrders
Child Table - tblOrderItems (ForeignKey is OrderID)
public class OrderItems
{
public int ID { get; set; }
public string Order { get; set; }
public string Status { get; set; }
public DateTime DataC { get; set; }
public int Item { get; set; }
}
public IEnumerable<OrderItems> LoadItems()
{
List<OrderItems> list = new List<OrderItems>();
string[] textArray = TxtOrder.Text.Split(new string[] { ronment.NewLine }, StringSplitOptions.None);
foreach (var text in textArray.Distinct())
{
var ctx = new DbContext();
var query = (from p in ctx.tblOrderItems.AsQueryable()
join m in ctx.tblOrders on p.RegistID equals m.RegistID
where m.Order.Contains(text)
select new OrderItems
{
ID = p.RegistTID,
Order = m.Order,
Status = p.Status,
DataC = m.DataC,
Item = p.Item
}).FirstOrDefault();
list.Add(query);
}
return list;
}
The problem: Querying like this in the Primary Key, I get correct values because I only get 1 record per item added in TxtOrder Textbox.
But I'm querying tblOrderItems and the tblOrderItems has many records related to 1 record in tblOrders and I can't get them all to my DataGridView.
To get the items instead of the item, you need to:
Use ToList instead of FirstOrDefault and AddRange instead of Add.

Group IEnumerable into a string

I wonder if someone could spare me a few minutes to give me some advice please?
I've created an IEnumerable list:
public class EmailBlock
{
public int alertCategory { get; set; }
public string alertName { get; set; }
public string alertURL { get; set; }
public string alertSnippet { get; set; } //Need to work out the snippet
}
List<EmailBlock> myEmailData = new List<EmailBlock>();
Which I then loop through some data (Umbraco content - not that that's really relevant!) and add items to the list.
myEmailData.Add(new EmailBlock { alertCategory = category.Id, alertName = alert.GetPropertyValue("pageTitle"), alertURL = alert.NiceUrl });
What ultimately I'd like to do is group the list by the alertCategory and then load each 'group' (another loop occurs later to check what members have subscribed to what alert category) into a variable which I can then use as an email's content.
You could use Linq's GroupBy() to do this:
using System.Linq
...
//Create a type to hold your grouped emails
public class GroupedEmail
{
public int AlertCategory { get; set; }
public IEnumerable<EmailBlock> EmailsInGroup {get; set; }
}
var grouped = myEmailData
.GroupBy(e => e.alertCategory)
.Select(g => new GroupedEmail
{
AlertCategory = g.Key,
EmailsInGroup = g
});
You can select to an anonymous type if required and project your sequence into whatever structure you require.
Linq has a nice group by statement:
var emailGroup = emailList.GroupBy(e => e.alertCategory);
Then you can loop through each grouping and do whatever you want:
foreach(var grouping in emailGroup)
{
//do whatever you want here.
//note grouping will access the list of grouped items, grouping.Key will show the grouped by field
}
Edit:
To retrieve a group after you have grouped them, just use Where for more than one or First for just one:
var group = emailGroup.First(g => g.Key == "name you are looking for");
or
var groups = emailGroup.Where(g => listOfWantedKeys.Contains(g.Key));
this is a lot more efficient than looping through every time you need to find something.

How to Order By list inside list using LINQ in C#

I want to Order by "SortKey" first list and second list inside first list, but I can't do it. Please get me your advice how to order lists using LINQ.
//Get Data and put in myList
List<Group1> myList = GetData();
//Sort
//Visual studio do not get compilation error but this code doesn't working at the run-time.
var SortedData = myList.Select(x => x).OrderBy(x=> x.SortKey).ThenBy(y=> y.Group2.OrderBy(x=> x.SortKey)).ToList();
Model:
public class Group1
{
public int Id {get;set;}
public string Name {get;set;}
public int Sortkey {get;set;}
public List<Group2> {get;set;}
}
public class Group2
{
public int Id {get;set;}
public string Name {get;set;}
public int Sortkey {get;set;}
}
You cannot re-order the innerlist with a LINQ query. The only way is to create a new ordered list. I suggest to use a simple loop and List.Sort:
List<Group1> myList = GetData();
myList.Sort((x1, x2) => x2.SortKey.CompareTo(x2.SortKey));
foreach(Group1 item in myList)
{
item.Group2.Sort((x1, x2) => x2.SortKey.CompareTo(x2.SortKey));
}
If you want to use LINQ (List.Sort is more efficient):
List<Group1> myList = GetData().OrderBy(x => x.SortKey).ToList();
foreach(Group1 item in myList)
{
item.Group2 = item.Group2.OrderBy(x => x.SortKey).ToList();
}
But why can't you order the lists in GetData?
I am not good with LINQ and i haven't tested this solution
but what about this:
HINT: This solution may not be good, because it has side effects (see comment on other answer)
assuming you have these classes:
public class Group1
{
public int Id {get;set;}
public string Name {get;set;}
public int Sortkey {get;set;}
public List<Group2> Categories {get;set;}
}
public class Group2
{
public int Id {get;set;}
public string Name {get;set;}
public int Sortkey {get;set;}
}
// Order first List with the first OrderBy
var sortedList = myList.OrderBy(
x =>
{
// x equals a element in the list
// foreach x you want to sort the second list
// and assign it back to x.Categories
x.Categories = x.Categories.OrderBy(y => y.Sortkey).ToList();
return x.Sortkey;
}).ToList();
I test this code and everything is working well.
var result = MyList.OrderBy(x => x.SortKey).ToList();
foreach (var item in model)
{
item.Group2 = item.Categories.OrderBy(x => x.SortKey).ToList();
}

LINQ to Lookup with distinct items and count

If I define a list as
public class ItemsList
{
public string structure { get; set; }
public string Unit { get; set; }
public double Dim { get; set; }
public double Amount { get; set; }
public int Order { get; set; }
public string Element { get; set; }
}
List<ItemsList> _itemsList = new List<ItemsList>();
I'm trying to get the a distinct count of structures in a Lookup with structure as the key and count of structure as the value.
At the moment I have
var sCount = from p in _itemsList
group p by p.Structure into g
select new { Structure = g.Key, Count = g.Count() };
but this just returns the data as an anonymous type. Can someone please help me with the syntax to get this into a Lookup using .ToLookup?
I suspect you actually want:
var lookup = _itemsList.ToLookup(p => p.Structure);
You can still count the items for any group:
foreach (var group in lookup)
{
Console.WriteLine("{0}: {1}", group.Key, group.Count());
}
... but you've also got the values within each group.
If you really just want the count, then it sounds like you don't want a lookup at all - you want a Dictionary, which you can get with:
var dictionary = _itemsList.GroupBy(p => p.Structure)
.ToDictionary(g => g.Key, g => g.Count());

how to add items to result of a linq select new command in C#?

in C# using linq i have a query like:
var result = from p in cart select new { p.Product.Title, p.Product.Price };
now i want to add some another items to result. For example adding:
int weight;
string message;
so that i can have something like:
foreach( var r in result)
{
dosomething(r.weight;)
dosomething(r.message);
dosomething(r.title);
dosomething(r.price);
}
is it possible? how should i do it?
You would need to create new items. Could you do something like this instead?
var result = from p in cart select new { Title = p.Product.Title,
Price = p.Product.Price,
Weight = 0,
Message = null };
Select new create anonymous type so you cannot add the property once it get created but one thing you can do is create your own type and assign property value in query and than assign other property value later on..
//your class will be
class MyClass
{
float weight {get;set;}
string Title {get;set;}
float price {get;set;}
string message {get;set;}
}
//select new will be
select new MyClass
{
Title = p.Product.Title,
price = p.Product.Price,
weight = 0,
message = string.empty
}
You can't do that. Anonymous types are normal types and they are fixed at compile time. You can't change them later.
EDIT:
You can create a container class for your result set and then select based on that:
class MyResult
class MyResult
{
public string Title { get; set; }
public double Price { get; set; }
public double Weight { get; set; }
public string Message { get; set; }
}
And then you can use:
var query = from t in cart
select new MyResult
{
Title = t.ProductTitle,
Price = t.Product.Price
};
Later you could do:
foreach( var r in result)
{
dosomething(r.Wight;)
dosomething(r.Message);
dosomething(r.Title);
dosomething(r.Price);
}
You can do the following :
var result = from p in cart select new { p.Product.Title, p.Product.Price, Weight = 55, Message ="message" };

Categories