Following are my two entities
Public Class A {
public int id {get;set}
public string name {get;set;}
public List<B> games {get;set}
}
Public Class B {
public int id {get;set}
public string name {get;set;}
public bool isActive {get;set;}
public int a_id {get;set;}
}
Object A has the following data
1, name1
2, name2
3, name3
Object B has the following data
1, cricket, true, 1
2, soccer, false, 1
3, snooket, false, 1
4, cricket, false, 2
5, soccer, true, 2
6, tennis, false, 2
7, poker, false, 2
8, cricket, false, 3
9, soccer, false, 3
10, tennis, true, 3
11, poker, false, 3
I want to my result set to contain only those rows from Object B where
isActive==true;
I tried all kind of queries i.e. with All, Any but I am unable to achieve the goal.
You want to filter your sub list, here you can use projection to bind your objects to a new set of objects filtered as you want.
Example :
var filteredList = listA.Select(o => new A
{
id = o.id,
name = o.name,
games = o.games.Where(g => g.isActive)
});
Related
Let's say I have two tables. I'm only showing what's necessary here, but the two tables ShoppingListA and ShoppingListB have other properties and FK to different objects, but they both have a "name" property.
public class ShoppingListA
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ShoppingListB
{
public int Id { get; set; }
public string Name { get; set; }
}
I have the following DTO
public class ShoppingListDto
{
public int Id { get; set; }
public string Name { get; set; }
public int Count {get; set;}
}
Further, I have a repo method which:
public async Task<List<ShoppingListDto>> GetShoppingLists()
{
var shoppingListsA = await dbContext.ShoppingListA.Select(shoppingList => new ShoppingListDto
{
Id = shoppingList.Id,
Name = shoppingList.Name,
}).ToListAsync();
var shoppingListsB = await dbContext.ShoppingListB.Select(shoppingList => new ShoppingListDto
{
Id = shoppingList.Id,
Name = shoppingList.Name,
}).ToListAsync()
var allShoppingLists = shoppingListsA.Concat(shoppingListsB).ToList();
return allShoppingLists;
}
When I return shoppingListsDto, I would like to know the count of how many times the same name appears across both tables. As an example.
let's say shoppingListA is:
[
{
id: 2342352235,
name: "Weekend Groceries"
},
{
id: 457457543,
name: "Dinner party"
},
]
let's say shoppingListB is:
[
{
id: 3795794697,
name: "BBQ stuff"
},
{
id: q845846q868,
name: "Dinner party"
},
]
then my GetShoppingLists method would return:
[
{
id: 3795794697,
name: "BBQ stuff",
count: 1,
},
{
id: q845846q868,
name: "Dinner party",
count: 2,
},
{
id: 2342352235,
name: "Weekend Groceries",
count: 1,
},
{
id: 457457543,
name: "Dinner party",
count: 2,
},
]
To collect count of overlapping properties you just need grouping of joined tables.
var query =
from a in dbContext.ShoppingListA
join b in dbContext.ShoppingListB on a.Name equals b.Name
group a by a.Name into g
select ShoppingListDto
{
Id = // which ID?
Name = g.Key,
Count = g.Count()
};
Whenever you have a sequence of similar items, and you want to make groups of these items, based on some common value, consider to use one of the overloads of Enumerable.GroupBy
In your case: you want to make groups of Shopping Lists, where every Shopping List in one group has the same value for Property name.
var shoppingListGroups = shoppinlists.GroupBy(shoppingList => shoppingList.Name,
// parameter resultSelector: for every Name, and all ShopplingLists with this name
// make one new:
(name, shoppingListsWithThisName) => new
{
Name = name,
ShoppingListsI = shoppingListsWithThisName.Select(shoppingList => new
{
shoppingList.Id,
Name = shoppingList.Name,
Count = shoppingListsWithThisName.Count(),
})
.ToList(),
});
In words: from your sequence of ShoppingLists, make groups of ShoppingLists where every ShoppingList in each group has the same value for property ShoppingList.Name. From every group Name, and all ShoppingLists in this group (which all have the same Name), make one object, containing the common name, and a list of objects containing the Id, the Name and the number of elements in the group (= all ShoppintLists with this name).
IMHO this is fairly useless, you already know the Name, why would you repeat this name for all elements in the group, and why would you repeat the same count for every element in the groups. The following would be way more efficient:
"Grocery Shopping" has 3 elements with Ids {10, 23, 14}
"Dinner Party" has 2 elements with Ids {11, 12}
"BBQ stuff" has 1 element with Id {18}
If you want that, the query will be much easier:
var shoppingListGroups = shoppinlists.GroupBy(shoppingList => shoppingList.Name,
(name, shoppingListsWithThisName) => new
{
Name = name,
Ids = shoppingListsWithThisName.Select(shoppingList => shoppingList.Id).ToList(),
}
In words: make groups of ShoppingLists that have the same value for property ShoppingList.Name. For every Group make one object, that contains a Name and a list of Ids. The Name is the common Name for all ShoppingLists in the group; the list contains the Ids of all ShoppingLists in the group. Every List has a property Count, so you also know the total number of elements in each group.
The result will be more efficient and have a more natural feeling.
I have a HashSet of 2000 items like this (the Index is not a property of the item):
Index LocationId UserId OtherProperty
1 1 1 abc
2 1 2 zyx
3 1 3 nvme
4 1 4 pcie
5 2 1 test
6 2 2 temp
7 2 3 etc
8 2 4 hah
...........................................
2000 500 4 last
If I do:
hashSet.GroupBy(o => o.LocationId)
.ToDictionary(g => g.Key, g => g.ToList());
I get a dictionary with 500 locations, each containing a list of 4 users.
But I need a dictionary of 2000 items, where the other properties are preserved, each having a list of 4 users. How do I do that?
Your question is not clear. I did a wild guess what you're trying and set up some examples for you:
static void Main(string[] args)
{
List<MyClass> list = new List<MyClass>()
{
new MyClass() { Index = 1, LocationId = 1, UserId = 1, OtherProperty = "abc" },
new MyClass() { Index = 2, LocationId = 1, UserId = 2, OtherProperty = "qwe" },
new MyClass() { Index = 3, LocationId = 1, UserId = 3, OtherProperty = "asd" },
new MyClass() { Index = 4, LocationId = 1, UserId = 1, OtherProperty = "yxc" },
new MyClass() { Index = 5, LocationId = 2, UserId = 2, OtherProperty = "acb" },
new MyClass() { Index = 6, LocationId = 2, UserId = 3, OtherProperty = "ghj" },
new MyClass() { Index = 7, LocationId = 2, UserId = 1, OtherProperty = "uio" },
new MyClass() { Index = 8, LocationId = 2, UserId = 2, OtherProperty = "zhn" }
};
// Index is Unique => We build a Dictionary with one object per index.
Dictionary<int, MyClass> dicIndexToObject = list.ToDictionary(d => d.Index);
// We got multiple objects per Locations => We need a Lookup
ILookup<int, MyClass> lookupLocationToObject = list.ToLookup(l => l.LocationId);
// If we ask with a key, we get a List:
IEnumerable<MyClass> tmp = lookupLocationToObject[1];
Console.WriteLine("--- What do we have per LocationId? ---");
foreach (MyClass obj1 in tmp)
{
Console.WriteLine(obj1.ToString());
}
ILookup<int, MyClass> lookupUserIdToObject = list.ToLookup(l => l.UserId);
Console.WriteLine("--- What do we have per UserId? ---");
foreach (MyClass obj2 in lookupUserIdToObject[1])
{
Console.WriteLine(obj2.ToString());
}
// What if you want to get deeper?
// What if we want to search for an index within a Location?
Dictionary<int, Dictionary<int, MyClass>> dicLocationToIndexToObject =
list.GroupBy(l => l.LocationId) // We group by location
.ToDictionary(g => g.Key, values => values.ToDictionary(k => k.Index)); // We form the grouping to a dictionary. Instead of accepting a List as value, we form another dictionary
// if we now want to search for a index in a specific location we do this:
Console.WriteLine("--- Let's get out object for Index '1' in location '1' ---");
Dictionary<int, MyClass> tmp2 = dicLocationToIndexToObject[1];
MyClass obj = tmp2[1];
Console.WriteLine(obj);
Console.WriteLine("--- Lets get all objects for UserId '1' in location '2' ---");
Dictionary<int, ILookup<int, MyClass>> dicLocationToUserIdLookup =
list.GroupBy(l => l.LocationId) // We group by location
.ToDictionary(g => g.Key, values => values.ToLookup(k => k.UserId));
foreach (MyClass obj3 in dicLocationToUserIdLookup[2][1])
{
Console.WriteLine(obj3.ToString());
}
}
public class MyClass
{
public int Index { get; set; }
public int LocationId { get; set; }
public int UserId { get; set; }
public string OtherProperty { get; set; }
public override string ToString()
{
return String.Format(" Index: {0}, LocationId: {1}, UserId: {2}, OtherProperty: {3}", this.Index, this.LocationId, this.UserId, this.OtherProperty);
}
}
i am trying a linq query to sort a group of elements and then bring a elements that satisfy particular condition to top.
for eg, if i have list of elements like below:
ID Names
1 Angie
2 Bret
3 Salva
4 cunnighma
5 maria
6 Galvin
7 Newton
8 Desmond
and if i pass condition as Name=Galvin then the resultset should be sorted first and then bring the value inn condition to top.The resultset would like below
ID Names
6 Galvin
1 Angie
2 Bret
4 cunnighma
8 Desmond
5 maria
7 Newton
3 Salva
One option is to create an extension method that can be used in your linq expression. The following solution does just that. I've made it work for the case of multiple matches as well.
The example code below will have the following output:
6:Galvin
1:Angie
2:Bret
4:cunnighma
8:Desmond
5:maria
7:Newton
3:Salva
Here's the code:
void Main()
{
// Setup the example data
var names = new List<Record>
{
new Record { Id = 1, Name = "Angie" },
new Record { Id = 2, Name = "Bret" },
new Record { Id = 3, Name = "Salva" },
new Record { Id = 4, Name = "cunnighma" },
new Record { Id = 5, Name = "maria" },
new Record { Id = 6, Name = "Galvin" },
new Record { Id = 7, Name = "Newton" },
new Record { Id = 8, Name = "Desmond" }
};
// Sort the list and move the matches to the top
var result = names
.OrderBy(x => x.Name)
.MoveToTop(x => x.Name.Contains("alvin"));
// Display the results to the console
result
.ToList()
.ForEach(x => Console.WriteLine($"{x.Id}:{x.Name}"));
}
public class Record
{
public int Id { get; set; }
public string Name { get; set; }
}
public static class EnumerableExtensions
{
public static IEnumerable<T> MoveToTop<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
var matches = list.Where(predicate);
return matches.Concat(list.Except(matches));
}
}
I have 2 collections need to create a 3 one if you like by merging the 2 and giving me a third one with all the unique items only
class Program
{
static void Main(string[] args)
{
ObservableCollection<Person> collectionA = new ObservableCollection<Person>
{
new Person {Id = 1, Name = "Name1", Surname = "Surname1"},
new Person {Id = 2, Name = "Name2", Surname = "Surname2"},
new Person {Id = 3, Name = "Name3", Surname = "Surname3"},
new Person {Id = 4, Name = "Name4", Surname = "Surname4"}
};
ObservableCollection<Person> collectionB = new ObservableCollection<Person>
{
new Person {Id = 5, Name = "Name5", Surname = "Surname5"},
new Person {Id = 2, Name = "Name2", Surname = "Surname2"},
new Person {Id = 6, Name = "Name6", Surname = "Surname6"},
new Person {Id = 4, Name = "Name4", Surname = "Surname4"}
};
ObservableCollection<Person> result=????
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
}
Any ideas?Thanks a lot
EDIT CLARIFICATION
I have collectionA, then I create collection B, compare the two collection add any item to FIND ALL THE ITEMS IN COLLECTIONB THAT DONT EXISTS IN COLLECTION A AND CREATE A RESULT COLLECTION.Hope clear now
If Id is a unique identifier of you person try this one:
ObservableCollection<Person> result = new ObservableCollection<Person>(collectionB
.Where(p => !collectionA.Any(p2=>p2.Id==p.Id)));
Edited answer:
ObservableCollection<Person> result = new ObservableCollection<Person>(collectionB.Except(collectionA));
Note that this will create a new collection that is not tied to the old collections - so if you add a person to collectionA, they will not show up in result automatically.
Newbie to LINQ, and trying to write the following query...
select
f.Section_ID,
f.Page_ID,
f.SortOrder,
f.Type
from
(
select
Section_ID,
min(SortOrder) as minSortOrder
from
ContentPages
group by
Section_ID
) as x
inner join
ContentPages as f on
f.Section_ID = x.Section_ID and
f.SortOrder = x.minSortOrder;
Notes:
'Section' has many 'ContentPages'
Sections are ordered by a 'SortOrder' field
ContentPages are also ordered by a 'SortOrder' field
Table: Section
Section_ID....Name.......SortOrder
....1.........One..........1......
....2.........Two..........3......
....3.........Three........2......
Table: ContentPage
Page_ID.......Section_ID.......Title..............SortOrder
....11.............1.......... Page One.............1......
....12.............1...........Page Two.............3......
....13.............2...........Page Three...........2......
....16.............2.......... Page Four............4......
....17.............2...........Page Eight...........5......
....18.............1...........Page Ten.............6......
The above query could possibly be written another way, so here's what I'm trying to do:
I need to return a list of the first ContentPage within each Section (when sorted by ContentPage.SortOrder)
Sort results by Section.SortOrder
Show Section.Name (join on Section_ID?) in the result as well
Last 2 points are not covered by the sql query above and are more of a 'nice to have'...
Desired Result
Page_ID.......Section_ID...SectionName.....Title..............SortOrder
....11.............1.........One......... Page One.............1......
....13.............2.........Two..........Page Three...........2......
Any help is appreciated. Thanks!
Here's my first attempt at it:
from sectionPage in pages
group sectionPage by sectionPage.Section_ID into sectionGroup
join page in pages on sectionGroup.Key equals page.Section_ID
where page.SortOrder == sectionGroup.Min(p => p.SortOrder)
orderby page.SortOrder
select page;
What happens is first we create a group on the section id so that we can get the minimum sort order later. Next, we join a new reference to pages in on the section id, and filter by SortOrder being the minimum from the section group. Note, for simple expressions like the Min() call, I prefer the inline lambda expression over another query.
Finally, we add an orderby to order the pages, and we return the page (note you can change this to certain fields if you prefer).
I think this is what you're looking for...
internal class Section
{
public int SectionId { get; set; }
public string Name { get; set; }
public int SortOrder { get; set; }
}
internal class ContentPage
{
public int PageId { get; set; }
public int SectionId { get; set; }
public string Title { get; set; }
public int SortOrder { get; set; }
}
static void Main(string[] args)
{
List<Section> sections = new List<Section>();
sections.Add(new Section() { SectionId = 1, Name = "One", SortOrder = 1 });
sections.Add(new Section() { SectionId = 2, Name = "Two", SortOrder = 3 });
sections.Add(new Section() { SectionId = 3, Name = "Three", SortOrder = 2 });
List<ContentPage> contentPages = new List<ContentPage>();
contentPages.Add(new ContentPage() { PageId = 11, SectionId = 1, Title = "Page One", SortOrder = 1 });
contentPages.Add(new ContentPage() { PageId = 12, SectionId = 1, Title = "Page Two", SortOrder = 3 });
contentPages.Add(new ContentPage() { PageId = 13, SectionId = 2, Title = "Page Three", SortOrder = 2 });
contentPages.Add(new ContentPage() { PageId = 16, SectionId = 2, Title = "Page Four", SortOrder = 4 });
contentPages.Add(new ContentPage() { PageId = 17, SectionId = 2, Title = "Page Eight", SortOrder = 5 });
contentPages.Add(new ContentPage() { PageId = 18, SectionId = 1, Title = "Page Ten", SortOrder = 6 });
var items = from section in sections
orderby section.SortOrder
join contentPage in
(from contentPage in contentPages
orderby contentPage.SortOrder
group contentPage by contentPage.SectionId into grp
select grp.FirstOrDefault())
on section.SectionId equals contentPage.SectionId
select new
{
PageId = contentPage.PageId,
SectionId = section.SectionId,
SectionName = section.Name,
Title = contentPage.Title,
SortOrder = section.SortOrder
};
foreach (var newItem in items)
{
Console.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}", newItem.PageId, newItem.SectionId, newItem.SectionName, newItem.Title, newItem.SortOrder));
}
}
Note that the sample data you provided shows a sort order of 3 for section 2, but your sample results list its sort order as 2.