Janis S.
Janis S.

Reputation: 2626

Linq nested collection filter

I have Brand and Area view models containing their respective Ids. Brand view model has a collection of Areas.

public class BrandViewModel
{
    public int Id { get; set; }
    private ObservableCollection<AreaViewModel> _areas;

    public ObservableCollection<AreaViewModel> Areas
    {
        get { return _areas; }
        set { Set(() => Areas, ref _areas, value); }
    }
}

I have SelectedAreas collection which has the matching Ids with the AreaViewModel.

I have collection of BrandViewModel. I would like to get collection of BrandViewModel which is filtered by selected areas. Tried statement below but Where clause needs a bool condition.

filteredBrandViewModels = brandViewModels.Where(b => b.Areas
        .Where(a => SelectedAreas.Select(sa => sa.Id).Contains(a.Id)));

Upvotes: 1

Views: 123

Answers (2)

Gilad Green
Gilad Green

Reputation: 37299

You can replace the inner Where with Any:

filteredBrandViewModels = brandViewModels.Where(b => 
    b.Areas.Any(a => SelectedAreas.Select(sa => sa.Id).Contains(a.Id)));

Then you can also change the Select to:

filteredBrandViewModels = brandViewModels.Where(b => 
    b.Areas.Any(a => SelectedAreas.Any(sa => sa.Id == a.Id)));

And last, in case of a lot of data, I'd recommend having the ids from SelectedAreas as a HashSet<int> so search will be an O(n) operation instead of O(n^2):

var hash = new HashSet<int>(SelectedAreas.Select(s => s.Id));
filteredBrandViewModels = brandViewModels.Where(b => b.Areas.Any(a => hash.Contains(a.Id)));

Upvotes: 2

darkpbj
darkpbj

Reputation: 2992

Linq methods for Enumerable Any and Intersect will be handy here:

filteredBrandViewModels = brandViewModels.Where(b =>
    b.Areas.Select(a=>a.Id).Intersect(SelectedAreas.Select(sa => sa.Id).Any()
)

Upvotes: 0

Related Questions