I have a list of Products that came from the database and from this list, I used LINQ and return as a List of Phone class.
List<Product> products = new List<Product>
{
new Product { ID = 1, Name = "Alcohol", Expired = false },
new Product { ID = 2, Name = "Phone", Expired = false },
new Product { ID = 2, Name = "Phone", Expired = false },
new Product { ID = 3, Name = "Computer", Expired = false },
new Product { ID = 4, Name = "Chair", Expired = false },
};
var results = from i in products.Where(o => o.Name == "Phone")
select new Phones
{
ID = i.ID,
Phone = i.Name,
isChild = i.Expired
};
//Update the isChild property
foreach (var item in results)
{
item.isChild = true;
}
public class Phones
{
public int ID { get; set; }
public string Phone { get; set; }
public bool isChild { get; set; }
}
I used to update the list of Phones using foreach loop. But the problem is when I checked the results variable it doesn't update the said items.
Thats because of deferred execution of the IEnumerable. Try casting your results ToList to immediate execute that query:
var results = (from i in products.Where(o => o.Name == "Phone")
select new Phones
{
ID = i.ID,
Phone = i.Name,
isChild = i.Expired
}).ToList();
If you won't - it would requery the products every time and you will work with a new set of Phones.
Related
I have an object:
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
}
I return a list that may look like the following:
List<Customer> CustomerList = new List<Customer>();
CustomerList.Add( new Customer { ID = 1, Name = "One", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 2, Name = "Two", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 3, Name = "Three", GroupID = 2 } );
CustomerList.Add( new Customer { ID = 4, Name = "Four", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 5, Name = "Five", GroupID = 3 } );
CustomerList.Add( new Customer { ID = 6, Name = "Six", GroupID = 3 } );
I want to return a linq query which will look like
CustomerList
GroupID =1
UserID = 1, UserName = "UserOne", GroupID = 1
UserID = 2, UserName = "UserTwo", GroupID = 1
UserID = 4, UserName = "UserFour", GroupID = 1
GroupID =2
UserID = 3, UserName = "UserThree", GroupID = 2
GroupID =3
UserID = 5, UserName = "UserFive", GroupID = 3
UserID = 6, UserName = "UserSix",
I tried from
Using Linq to group a list of objects into a new grouped list of list of objects
code
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID)
.Select(grp => grp.ToList())
.ToList();
works but does not give the desired output.
var groupedCustomerList = CustomerList.GroupBy(u => u.GroupID)
.Select(grp =>new { GroupID =grp.Key, CustomerList = grp.ToList()})
.ToList();
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID, u=>{
u.Name = "User" + u.Name;
return u;
}, (key,g)=>g.ToList())
.ToList();
If you don't want to change the original data, you should add some method (kind of clone and modify) to your class like this:
public class Customer {
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
public Customer CloneWithNamePrepend(string prepend){
return new Customer(){
ID = this.ID,
Name = prepend + this.Name,
GroupID = this.GroupID
};
}
}
//Then
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID, u=>u.CloneWithNamePrepend("User"), (key,g)=>g.ToList())
.ToList();
I think you may want to display the Customer differently without modifying the original data. If so you should design your class Customer differently, like this:
public class Customer {
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
public string Prefix {get;set;}
public string FullName {
get { return Prefix + Name;}
}
}
//then to display the fullname, just get the customer.FullName;
//You can also try adding some override of ToString() to your class
var groupedCustomerList = CustomerList
.GroupBy(u => {u.Prefix="User", return u.GroupID;} , (key,g)=>g.ToList())
.ToList();
is this what you want?
var grouped = CustomerList.GroupBy(m => m.GroupID).Select((n) => new { GroupId = n.Key, Items = n.ToList() });
var result = from cx in CustomerList
group cx by cx.GroupID into cxGroup
orderby cxGroup.Key
select cxGroup;
foreach (var cxGroup in result) {
Console.WriteLine(String.Format("GroupID = {0}", cxGroup.Key));
foreach (var cx in cxGroup) {
Console.WriteLine(String.Format("\tUserID = {0}, UserName = {1}, GroupID = {2}",
new object[] { cx.ID, cx.Name, cx.GroupID }));
}
}
The desired result can be obtained using IGrouping, which represents a collection of objects that have a common key in this case a GroupID
var newCustomerList = CustomerList.GroupBy(u => u.GroupID)
.Select(group => new { GroupID = group.Key, Customers = group.ToList() })
.ToList();
I have a table of WorldEvents. Each WorldEvent has a list of Presentations, that happened in some country, regarding that WorldEvent
public class WorldEvent
{
public int ID { get; set; }
public string Name { get; set; }
public List<Presentation> PresentationList { get; set; }
}
public class Presentation
{
public int ID { get; set; }
public string Name { get; set; }
public string Country { get; set; }
}
public class WorldEventService
{
public List<WorldEvent> GetWorldEvents()
{
List<WorldEvent> worldEventList = new List<WorldEvent>();
List<Presentation> presentationList = new List<Presentation>();
// Create list of Presentations for WorldEvent_1
presentationList = new List<Presentation>()
{
new Presentation() { ID = 1, Name = "Presentation_1", Country = "Germany",},
new Presentation() { ID = 2, Name = "Presentation_2", Country = "UK",},
new Presentation() { ID = 3, Name = "Presentation_3", Country = "UK",},
};
// Add WorldEvent_1 to the list of WorldEvents
worldEventList.Add(new WorldEvent()
{
ID = 1,
Name = "WorldEvent_1",
PresentationList = presentationList,
});
// Create list of Presentations for WorldEvent_2
presentationList = new List<Presentation>()
{
new Presentation() { ID = 4, Name = "Presentation_4", Country = "USA",},
new Presentation() { ID = 5, Name = "Presentation_5", Country = "UK",},
new Presentation() { ID = 6, Name = "Presentation_6", Country = "Japan",},
};
// Add WorldEvent_2 to the list of WorldEvents
worldEventList.Add(new WorldEvent()
{
ID = 2,
Name = "WorldEvent_2",
PresentationList = presentationList,
});
// Create list of Presentations for WorldEvent_3
presentationList = new List<Presentation>()
{
new Presentation() { ID = 7, Name = "Presentation_7", Country = "France",},
new Presentation() { ID = 8, Name = "Presentation_8", Country = "Germany",},
new Presentation() { ID = 9, Name = "Presentation_9", Country = "Japan",},
};
// Add WorldEvent_3 to the list of WorldEvents
worldEventList.Add(new WorldEvent()
{
ID = 3,
Name = "WorldEvent_3",
PresentationList = presentationList,
});
return worldEventList;
}
}
Now - how can I get a list of WorldEvents, whose Presentations took place in the UK.
And - in the list of my interest, WorldEvents should contain info about those UK Presentations only.
In other word, I need this as result:
WorldEvent_1(Presentation_2, Presentation_3)
WorldEvent_2(Presentation_5)
If I've understood what you want. There are many ways to do this, however you can filter first, then recreate your WorldEvents with the filtered list of Presentation
var country = "UK";
var result = worldEventList.Where(x => x.PresentationList.Any(y => y.Country == country))
.Select(x => new WorldEvent()
{
ID = x.ID,
Name = x.Name,
PresentationList = x.PresentationList
.Where(y => y.Country == country)
.ToList()
}).ToList();
or as noted by Gert Arnold in the comments you could filter after the fact
var result = worldEventList.Select(x => new WorldEvent()
{
ID = x.ID,
Name = x.Name,
PresentationList = x.PresentationList
.Where(y => y.Country == country).ToList()
}).Where(x => x.PresentationList.Any())
.ToList();
Note : Because this is not projecting (selecting) each Presentation, any change you make to a Presentation in the result will be reflected in the original data. If you don't want this, you will need to recreate each Presentation
var worldEvent = new WorldEventService.GetWorldEvents();
var filter = "";//userInput
var filteredResult = worldEvent.Select(r => new WorldEvent
{
PresentationList = r.PresentationList.Where(c => c.Country == filter).ToList(),
ID = r.Id,
Name = r.Name
}).ToList();
public static List<WorldEvent> Filter(string Country, List<WorldEvent> events) {
var evs = from ev in events.Where(x => x.PresentationList.Any(y => y.Country == Country))
let targetPres = from pres in ev.PresentationList
where pres.Country == Country
select pres
select new WorldEvent {
ID = ev.ID,
Name = ev.Name,
PresentationList = targetPres.ToList()
};
return evs.ToList();
}
Not sure if my understanding is correct, I guess there's a one to many relationship between your WorldEvent and Presentation table. So if you'd like to get all the WorldEvents and its related Presentations which take place in UK, by using EntityFramework, you can try this:
worldEventContext
.Include(PresentationContext)
.Select(
w => new
{
w.ID,
w.Name,
PresentationList = w.PresentationContext.Where(p => p.Country == "UK")
})
What's the best way to flatten a query that produces a collection that looks like this?
Instead of two rows for ClaimType Target, I want to produce a linq query or expression that has one row for ClaimType Target with both values of Tools and Compass in the same column.
ClaimType | ClaimValue
Target | Tools;Compass
Any ideas, I'm having a total brain cloud on this!
Here is how I would do this:
var claims = new []
{
new { ClaimType = "Redirect Url", ClaimValue = "https://www.thing.com/" },
new { ClaimType = "Target", ClaimValue = "Tools" },
new { ClaimType = "Target", ClaimValue = "Compass" },
};
var query =
from claim in claims
group claim by claim.ClaimType into claim_groups
select new
{
ClaimType = claim_groups.Key,
ClaimValues = String.Join(";", claim_groups.Select(x => x.ClaimValue)),
};
That will give you this:
Since I don't have the table I have created list of objects to simulate your data I hope this might help
List<item> items = new List<item>();
items.Add(new item { id = 1, name = "A", CliamId = "6", ClaimValue = "Any" });
items.Add(new item { id = 1, name = "Target", CliamId = "8", ClaimValue = "Tools" });
items.Add(new item { id = 1, name = "Target", CliamId = "9", ClaimValue = "Compass" });
var query = from i in items
group i by i.name
into g
select g;
foreach(var item in query)
{
Console.Write(string.Format("{0} ", item.Key));
foreach(var row in item)
{
Console.Write(string.Format("{0} ",row.ClaimValue));
}
Console.WriteLine();
}
Console.ReadLine();
}
// end of the class
}
class item
{
public int id { get; set; }
public string name { get; set; }
public string CliamId { get; set; }
public string ClaimValue { get; set; }
// end of the calss
}
The Result :
I have an object:
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
}
I return a list that may look like the following:
List<Customer> CustomerList = new List<Customer>();
CustomerList.Add( new Customer { ID = 1, Name = "One", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 2, Name = "Two", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 3, Name = "Three", GroupID = 2 } );
CustomerList.Add( new Customer { ID = 4, Name = "Four", GroupID = 1 } );
CustomerList.Add( new Customer { ID = 5, Name = "Five", GroupID = 3 } );
CustomerList.Add( new Customer { ID = 6, Name = "Six", GroupID = 3 } );
I want to return a linq query which will look like
CustomerList
GroupID =1
UserID = 1, UserName = "UserOne", GroupID = 1
UserID = 2, UserName = "UserTwo", GroupID = 1
UserID = 4, UserName = "UserFour", GroupID = 1
GroupID =2
UserID = 3, UserName = "UserThree", GroupID = 2
GroupID =3
UserID = 5, UserName = "UserFive", GroupID = 3
UserID = 6, UserName = "UserSix",
I tried from
Using Linq to group a list of objects into a new grouped list of list of objects
code
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID)
.Select(grp => grp.ToList())
.ToList();
works but does not give the desired output.
var groupedCustomerList = CustomerList.GroupBy(u => u.GroupID)
.Select(grp =>new { GroupID =grp.Key, CustomerList = grp.ToList()})
.ToList();
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID, u=>{
u.Name = "User" + u.Name;
return u;
}, (key,g)=>g.ToList())
.ToList();
If you don't want to change the original data, you should add some method (kind of clone and modify) to your class like this:
public class Customer {
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
public Customer CloneWithNamePrepend(string prepend){
return new Customer(){
ID = this.ID,
Name = prepend + this.Name,
GroupID = this.GroupID
};
}
}
//Then
var groupedCustomerList = CustomerList
.GroupBy(u => u.GroupID, u=>u.CloneWithNamePrepend("User"), (key,g)=>g.ToList())
.ToList();
I think you may want to display the Customer differently without modifying the original data. If so you should design your class Customer differently, like this:
public class Customer {
public int ID { get; set; }
public string Name { get; set; }
public int GroupID { get; set; }
public string Prefix {get;set;}
public string FullName {
get { return Prefix + Name;}
}
}
//then to display the fullname, just get the customer.FullName;
//You can also try adding some override of ToString() to your class
var groupedCustomerList = CustomerList
.GroupBy(u => {u.Prefix="User", return u.GroupID;} , (key,g)=>g.ToList())
.ToList();
is this what you want?
var grouped = CustomerList.GroupBy(m => m.GroupID).Select((n) => new { GroupId = n.Key, Items = n.ToList() });
var result = from cx in CustomerList
group cx by cx.GroupID into cxGroup
orderby cxGroup.Key
select cxGroup;
foreach (var cxGroup in result) {
Console.WriteLine(String.Format("GroupID = {0}", cxGroup.Key));
foreach (var cx in cxGroup) {
Console.WriteLine(String.Format("\tUserID = {0}, UserName = {1}, GroupID = {2}",
new object[] { cx.ID, cx.Name, cx.GroupID }));
}
}
The desired result can be obtained using IGrouping, which represents a collection of objects that have a common key in this case a GroupID
var newCustomerList = CustomerList.GroupBy(u => u.GroupID)
.Select(group => new { GroupID = group.Key, Customers = group.ToList() })
.ToList();
How can I group by with multiple columns using lambda?
I saw examples of how to do it using linq to entities, but I am looking for lambda form.
var query = source.GroupBy(x => new { x.Column1, x.Column2 });
I came up with a mix of defining a class like David's answer, but not requiring a Where class to go with it. It looks something like:
var resultsGroupings = resultsRecords.GroupBy(r => new { r.IdObj1, r.IdObj2, r.IdObj3})
.Select(r => new ResultGrouping {
IdObj1= r.Key.IdObj1,
IdObj2= r.Key.IdObj2,
IdObj3= r.Key.IdObj3,
Results = r.ToArray(),
Count = r.Count()
});
private class ResultGrouping
{
public short IdObj1{ get; set; }
public short IdObj2{ get; set; }
public int IdObj3{ get; set; }
public ResultCsvImport[] Results { get; set; }
public int Count { get; set; }
}
Where resultRecords is my initial list I'm grouping, and its a List<ResultCsvImport>. Note that the idea here to is that, I'm grouping by 3 columns, IdObj1 and IdObj2 and IdObj3
if your table is like this
rowId col1 col2 col3 col4
1 a e 12 2
2 b f 42 5
3 a e 32 2
4 b f 44 5
var grouped = myTable.AsEnumerable().GroupBy(r=> new {pp1 = r.Field<int>("col1"), pp2 = r.Field<int>("col2")});
Further to aduchis answer above - if you then need to filter based on those group by keys, you can define a class to wrap the many keys.
return customers.GroupBy(a => new CustomerGroupingKey(a.Country, a.Gender))
.Where(a => a.Key.Country == "Ireland" && a.Key.Gender == "M")
.SelectMany(a => a)
.ToList();
Where CustomerGroupingKey takes the group keys:
private class CustomerGroupingKey
{
public CustomerGroupingKey(string country, string gender)
{
Country = country;
Gender = gender;
}
public string Country { get; }
public string Gender { get; }
}
class Element
{
public string Company;
public string TypeOfInvestment;
public decimal Worth;
}
class Program
{
static void Main(string[] args)
{
List<Element> elements = new List<Element>()
{
new Element { Company = "JPMORGAN CHASE",TypeOfInvestment = "Stocks", Worth = 96983 },
new Element { Company = "AMER TOWER CORP",TypeOfInvestment = "Securities", Worth = 17141 },
new Element { Company = "ORACLE CORP",TypeOfInvestment = "Assets", Worth = 59372 },
new Element { Company = "PEPSICO INC",TypeOfInvestment = "Assets", Worth = 26516 },
new Element { Company = "PROCTER & GAMBL",TypeOfInvestment = "Stocks", Worth = 387050 },
new Element { Company = "QUASLCOMM INC",TypeOfInvestment = "Bonds", Worth = 196811 },
new Element { Company = "UTD TECHS CORP",TypeOfInvestment = "Bonds", Worth = 257429 },
new Element { Company = "WELLS FARGO-NEW",TypeOfInvestment = "Bank Account", Worth = 106600 },
new Element { Company = "FEDEX CORP",TypeOfInvestment = "Stocks", Worth = 103955 },
new Element { Company = "CVS CAREMARK CP",TypeOfInvestment = "Securities", Worth = 171048 },
};
//Group by on multiple column in LINQ (Query Method)
var query = from e in elements
group e by new{e.TypeOfInvestment,e.Company} into eg
select new {eg.Key.TypeOfInvestment, eg.Key.Company, Points = eg.Sum(rl => rl.Worth)};
foreach (var item in query)
{
Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Points.ToString());
}
//Group by on multiple column in LINQ (Lambda Method)
var CompanyDetails =elements.GroupBy(s => new { s.Company, s.TypeOfInvestment})
.Select(g =>
new
{
company = g.Key.Company,
TypeOfInvestment = g.Key.TypeOfInvestment,
Balance = g.Sum(x => Math.Round(Convert.ToDecimal(x.Worth), 2)),
}
);
foreach (var item in CompanyDetails)
{
Console.WriteLine(item.TypeOfInvestment.PadRight(20) + " " + item.Balance.ToString());
}
Console.ReadLine();
}
}