I have a List of :
public class GT
{
public string ActivityName { get; set; }
public int Seconds { get; set; }
}
And the ActivityName could repeat through the iteration and what I want to do is, regroup all the items that have the same name and calculate the average of seconds of these specifics items. I tried to use Distinct but it didn't group them.
You should use GroupBy instead of Distinct:
List<GT> list = /*...*/;
var query = list.GroupBy(x => x.ActivityName, (k,g) => new { ActivityName = k, AverageTimeInSeconds = g.Average(x => x.Seconds) });
var groups = items.GroupBy(p => p.ActivityName)
.Select(g => new
{
ActivityName = g.Key,
Average = g.Average(t => t.Seconds)
}).ToList();
Related
I'd like to get one list of IDs from all nested entities.
Code:
// Entities
class Floor
{
public int Id { get; set; }
public ICollection<Room> Rooms { get; set; } = new List<Room>();
}
class Room
{
public int Id { get; set; }
public ICollection<Chair> Chairs { get; set; } = new List<Chair>();
}
class Chair
{
public int Id { get; set; }
}
// Setup
var floor = new Floor() { Id = 1000 };
var room = new Room() { Id = 100 };
var chair = new Chair() { Id = 10 };
room.Chairs.Add(chair);
floor.Rooms.Add(room);
var floors = new List<Floor>() { floor };
// Select all IDs
var ids = floors.???
Expected result:
{ 10, 100, 1000 }
What I've tried. It selects IDs only from the deepest level, not all of them:
// Select all IDs
var ids = floors
.SelectMany(f => f.Rooms)
.SelectMany(r => r.Chairs)
.Select(ch => ch.Id)
.ToList();
SelectMany is what you need together with Append:
var ids = floors
.SelectMany(f => f.Rooms
.SelectMany(r => r.Chairs
.Select(c => c.Id).Append(r.Id)).Append(f.Id));
Your current code flattens the hierarchy to collection of Chair and selects only their ids.
With pure LINQ you can do via nesting SelectMany and using Append/Prepend:
var ids = floors
.SelectMany(f => f.Rooms
.SelectMany(r => r.Chairs
.Select(ch => ch.Id) // select chairs ids
.Append(r.Id)) // append "current" room id to it's collection of chair ids
.Append(f.Id)) // append "current" floor id to it's collection of rooms and chairs ids
.ToList();
An ugly hack would be to append "fakes" to the child rooms/chairs with the ID of their parent:
var ids = floors
.SelectMany(f => f.Rooms.Append(new Room { Id = f.Id }))
.SelectMany(r => r.Chairs.Append(new Chair { Id = r.Id }))
.Select(ch => ch.Id)
.ToList();
It can be done with a recursive helper function like this:
IEnumerable<int> CollectIds<T>(T x) => x switch {
Floor f => f.Rooms.SelectMany(CollectIds).Prepend(f.Id),
Room r => r.Chairs.SelectMany(CollectIds).Prepend(r.Id),
Chair c => Enumerable.Repeat(c.Id, 1),
_ => throw new NotSupportedException()
};
Usage:
var ids = floors
.SelectMany(CollectIds)
.ToList();
You could consider extracting this function into a common interface to avoid the awkward type switch and the recursion.
I'm stuck on a Linq-to-SQL query. I have a table of items, with multiple items per user. I want to get the list of all the latest items per user. This is what I have:
var TheList = (from t in MyDataContext.TheTable
where t.SomeDate > DateTime.UtcNow.AddMonths(-3)
group t by t.UserID into TheUserGroups
from g in TheGroups
orderby g.SomeDate descending
select new SomeObject()
{
TheUserID = g.UserID,
.....
}).ToList();
The problem is that it's returning all the items of every user instead of the most recent element per user. What do I need to change to get the expected result?
Try following :
var TheList = (from t in MyDataContext.TheTable
where t.SomeDate > DateTime.UtcNow.AddMonths(-3)
orderby g.SomeDate descending
select new SomeObject()
{
TheUserID = g.UserID,
})
.GroupBy(x => x.TheUserID)
.Select(x => x.FirstOrDefault())
.ToList();
If I understood you correctly:
public class Order
{
public int OrderId { get; set; }
public int UserId { get; set; }
public DateTime Date { get; set; }
public string ItemName { get; set; }
}
table.Where(o => o.Date < DateTime.UtcNow.AddMonths(-3))
.GroupBy(o => o.UserId)
.Select(g => new { UserId = g.Key, LastOrder = g.OrderByDescending(o => o.Date).FirstOrDefault() })
.ToList();
I have List collection of Message objects.
public class Message
{
public int Id { get; set; }
public string Body { get; set; }
public string Sender { get; set; }
public DateTime Timestamp { get; set; }
}
I want to get only one message with most recent Timestamp for each sender. How do I do it using LINQ?
You need to group by Sender and then get the Max Timestamp from each group like:
var query = list.GroupBy(r => r.Sender)
.Select(grp => new
{
Sender = grp.Key,
RecentTimeStamp = grp.Max(r => r.Timestamp)
});
Or you can sort the TimeStamp in group by descending order and get the first element like:
var query = list.GroupBy(r => r.Sender)
.Select(grp => new
{
Sender = grp.Key,
RecentTimeStamp = grp.OrderByDescending(r => r.Timestamp).FirstOrDefault()
});
var q = from n in table
group n by n.Senderinto g
select g.OrderByDescending(t=>t.Timestamp).FirstOrDefault();
I have a nested list of objects. That I need to group by identifierA and Sum its numeric properties, nested list shall group respectively:
public class TypeA
{
public String identifierA{ get; set; }
public Int32 number { get; set; }
public List<TypeB> nestedList { get; set; }
}
public class TypeB
{
public String identifierB { get; set; }
public Int32 otherNumber { get; set; }
}
So I'm expecting something like this:
var List<TypeA> groupedList = (from a in TypeAList
group a by a.identifierA
into groupedData
select new TypeA
{
identifierA = groupedData.Key,
number = groupedData.Sum(g => g.number ),
nestedList = //HOW TO GROUP NESTED PART?
}).ToList();
I think that this will resolve your issue.
List<TypeA> list = TypeAList
.GroupBy(a => a.identifierA)
.Select(
g =>
new TypeA
{
identifierA = g.Key,
number = g.Sum(n => n.number),
nestedList =
g.SelectMany(l => l.nestedList)
.GroupBy(b => b.identifierB)
.Select(
gg =>
new TypeB
{
identifierB = gg.Key,
otherNumber = gg.Sum(b => b.otherNumber)
}).ToList()
}).ToList();
SelectMany takes an IEnumerable<SomethingWithAnIEnumerable> and flattens all the SomethingWithAnIEnumerable's selected IEnumerables into a single IEnumerable:
nestedList = groupedData.SelectMany(pa => pa.nestedList).ToList()
use SelectMany
if you want to group the list into one use
nestedList = groupedData.SelectMany(d=>d.nestedList)
and if you want Sum of that list, use
nestedList = groupedData.SelectMany(d=>d.nestedList).Sum(o=>o.otherNumber)
I think your IdentfierB might be a key of some kind, and your result should reflect Grouped and Summed TypeBs.
List<TypeA> groupedList = TypeAList
.GroupBy(a => a.identifierA)
.Select(g => new TypeA()
{
identierA = g.Key,
number = g.Sum(a => a.number)
nestedList = g.SelectMany(a => a.nestedList)
.GroupBy(b => b.identifierB)
.Select(g2 => new TypeB()
{
identifierB = g2.Key,
otherNumber = g2.Sum(b => b.otherNumber)
}
}
I have two classes:
class Customer
{
public string Name { get; set; }
public string ZipCode { get; set; }
public List<Order> OrderList { get; set; }
}
class Order
{
public string OrderNumber { get; set; }
}
Using LINQ, i want to get list of Orders group by ZipCode. If Zipcode "12121" has 10 customers and each has 2 orders then it should return me only one Zipcode with the list of 20 orders.
I am trying to do it like this but not able to figure out whats wrong
var orders = br.CustOrderList
.Select(r => new
{
r.ZipCode,
r.Name,
r.OrderList
})
.GroupBy(x => new { x.ZipCode, x.OrderList});
Any help please?
This should do what you want:
var orders = br.CustOrderList
.GroupBy(x => x.ZipCode)
.Select(g => new
{
ZipCode = g.Key,
Orders = g.SelectMany(x => x.OrderList)
});
var orders = br.CustOrderList
.Select(r => new
{
r.ZipCode,
r.Name,
r.OrderList
})
.GroupBy(x => x.ZipCode);
You just want to group by the ZipCode so just group by that
Ah yea just try
var order = br.CustOrderList
.GroupBy(x = x.ZipCode);
No need to select new items out of the list