Given the following code:
var filtered = (from a in lijst select a);
foreach (string brandstof in checkedListBoxHoofdbrandstof.CheckedItems)
{
MessageBox.Show(brandstof);
filtered = (from a in lijst where a.Hoofdbrandstof.Contains(brandstof) select a);
}
MessageBox.Show(filtered.Count().ToString());
lijst is a List of a class , with about 16000 items
When checkedListBoxHoofdbrandstof.CheckedItems contains more than 1 item, the query only uses the results from the last where-clause.
For example: I have 2 values, A and B, and despite the fact that A returns 100 rows, and B returns 50 rows, only the last 50 rows are included as a result. A is not included in the results anymore.
I tried using a.Hoofdbrandstof.Any, but that results in an error about types. I also tried a.Hoofdbrandstof.Equals, with the same results.
Does anyone know how I can combine these results, so that both the results from A and B are in var filtered?
The simple way:
var checkedItems = checkedListBoxHoofdbrandstof.CheckedItems;
var filtered = from a in lijst
where checkedItems.Contains(a.Hoofdbrandstof)
select a
But complexity of this method if O(n^2) to reduce it to O(n) use a Join operation
var checkedItems = checkedListBoxHoofdbrandstof.CheckedItems.Cast<string>().ToList();
var filtered = from a in lijst
join checkedItem in checkedItems on a.Hoofdbrandstof equals checkedItem
select a
Related
I have a method that accepts two List<int> for which I need to get data from the database based on the List<>s.
So, I receive a List<PersonId> and List<NationalityId> for example, and I need to get a result set where records match the PersonIds and NationalistIds.
public List<PersonDTO> SearchPeople(List<int> persons, Lisy<int> nationalities)
{
var results = (from c in myDbContect.People where .... select c).ToList();
}
Note that I think Lists might be null.
Is there an efficient way?
I was going to try:
where ((persons != null && persons.Count > 0) && persons persons.Contains(x=>x.PersonId))
But this would generate rather inefficient SQL, and as I add more search parameters, the linq may get very messy.
Is there an efficient way to achieve this?
The join method may be easy to read, but the issue I face is that IF the input list is empty, then it shouldn't filter. That is, if nationalities is empty, don't filter any out:
var results = (from c in entities.Persons
join p in persons on c.PersonId equals b
join n in nationalities on c.NationalityId equals n
equals n
select c).ToList();
This would return no results if any of the lists were empty. Which, is bad.
If you join an IQueryable with an IEnumerable (in this case, entities.Persons and persons), your filtering will not happen within your query. Instead, your IQueryable is enumerated, retrieving all of your records from the database, while the join is performed in memory using the IEnumerable join method.
To perform your filtering against a list within your query, there are two main options:
Join using an IQueryable on both sides. This might be possible if your list of ids comes from the execution of another query, in which case you can use the underlying query in your join instead of the resulting set of ids.
Use the contains operator against your list. This is only possible with small lists, because each additional id requires its own query parameter. If you have many ids, you can possibly extend this approach with batching.
If you want to skip filtering when the list is empty, then you might consider using the extension method invocation instead of the LINQ syntax. This allows you to use an if statement:
IQueryable<Person> persons = entities.persons;
List<int> personIds = new List<int>();
if(personIds.Count > 0)
{
persons = persons.Where(p => personIds.Contains(p.PersonId));
}
var results = persons.ToList();
Note that the Where predicate uses option #2 above, and is only applied if there are any ids in the collection.
If you want to get all the records for persons for example if the list is empty and then filter by nationalityId list if its not empty you can do something like this:
List<int> personsIds = ...;
List<int> nationalitiesIds = ...;
var results = (from c in entities.Persons
join p in persons on c.PersonId equals b
join n in nationalities on c.NationalityId equals n
where ((personsIds == null || personsIds.Contains(p.Id))
&& (nationalitiesIds == null || nationalitiesIds.Contains(n.Id))
select c).ToList();
I have Rows object that is IEnumerable<dynamic>, it has 5 properties (columns) and 100 rows. One of the properties/columns is Group, only 2 distinct groups out of 100 rows, so first I run a distinct against it:
IEnumerable<dynamic> Groups = Rows.Select(x => x.Group).Distinct();
This works, no error.
Then I want to go back to my Rows object and loop through them where this group = the group in Rows, like this:
foreach (string Group in Groups)
{
IEnumerable<dynamic> GroupData =
from rowdata in Rows
where rowdata.Group = #Group
select rowdata;
But I get this error on the last line:
'WebMatrix.Data.DynamicRecord' does not contain a definition for 'Group'
Anyone knows why this isn't working?
Surely I can do this another way, but I wanted to use c# select statement instead. How can I though?
Edit to show usage:
foreach (var row in GroupData){
string ThisGroup = row.Group
}
...
Instead of selecting twice, group on the Group value:
IEnumerable<IGrouping<string, dynamic>> groups = Rows.GroupBy(x => (string)x.Group);
Now you can just loop through the result:
foreach (IGrouping<string, dynamic> group in groups) {
...
}
The IGrouping<> object has a Key property which is the value that you grouped on, and it's also a collection of the values in the group.
IEnumerable<classB> list = getItems();
//dt is datatable
list = list.Where(x => Convert.ToInt32( !dt.Columns["Id"]) == (x.Id));
I want to only keep the items in the list which match in datatable id column. The rest are removed. I m not doing it right.
The datatable can have: ID - 1,3,4,5,7
The list can have: ID - 1,2,3,4,5,6,7,8,9,10
I want the output list to have: ID - 1,3,4,5,7
Your code won't work because you're comparing a definition of a column to an integer value. That's not a sensible comparison to make.
What you can do is put all of the values from the data table into a collection that can be effectively searched and then get all of the items in the list that are also in that collection:
var ids = new HashSet<int>(dt.AsEnumerable()
.Select(row => row.Field<int>("Id"));
list = list.Where(x => ids.Contains(x.Id));
Try this one
var idList = dt.AsEnumerable().Select(d => (int) d["Id"]).ToList();
list = list.Where(x => idList.Contains(x.Id));
You can't do it like that. Your dt.Columns["Id"] returns the DataColumn and not the value inside that column in a specific datarow. You need to make a join between two linq query, the first one you already have, the other you need to get from the DataTable.
var queryDt = (from dtRow in dt
where !dtRow.IsNull("Id")
select int.Parse(dtRow["Id"])).ToList();
Now the join
var qry = from nonNull in queryDt
join existing in list on nonNull equals list.id
I have a List and a DataTable which contains a column to match the IDs in the list. I need to identify all IDs in my list that are not in the DataTable. I tried getting an IEnumberable DataRow and joining that to the list but I'm not able to identify the missing ones.
Here is my code and what I've tried...
List<int> JobIdList = (from i in EntryItems select i.JobID.Value).ToList<int>();
IEnumerable<DataRow> rowInfo = JobBLL.JobsExist(JobIdList).AsEnumerable();
var MissingList = (from rec in rowInfo
join id in JobIdList
on rec.Field<int>("JobID") equals id
into grouping
from id in grouping.DefaultIfEmpty()
select new { id }).ToList();
if (MissingList.Count > 0) { // Show message and exit }
The problem is that this returns the items in the data table that ARE found. Let's say I have 1, 2, and 3 in my list but my data table only has 1 and 3. I want to have 2 in MissingList.
Any thoughts?
var jobIdList = new HashSet<int>(from i in EntryItems select i.JobID.Value);
var rows = JobBLL.JobsExist(jobIdList).AsEnumerable();
var foundIds = (from x in rows select x.Field<int>("JobID")).ToList();
var missingIds = jobIdList.Except(foundIds);
You need to add the below line of code into your code.
var missingIds = JobIdList.Except(MissingList);
This is a complete Newbie question and I understand but how do I transfer these two distinct Enumerable collections to a single ObservableCollections?
var distinctLine1 = (from z in list
orderby z.ItemLine1
select z.ItemLine1).Distinct();
var distinctLine2 = (from z in list
orderby z.ItemLine2
select z.ItemLine2).Distinct();
foreach (var item in distinctLine1)
{
}
Sorry did change ObservableCollectionsList to ObservableCollections
ItemLine1 and ItemLine2 are both strings
I suppose you could probabl also call Distinct on union to exclude possible duplicates.
var union = distinctLine1.Union(distinctLine2).Distinct();
Or just
var union = distinctLine1.Union(distinctLine2);
And then simply create the target collection with ObservableCollection Constructor (IEnumerable):
var result = new ObservableCollection<string>(union);