How to "query" List<T> - c#

Say I have,
List<ExampleType> example;
Somewhere it has been populated with let's say 10 objects of ExampleType.
ExampleType looks like this:
class ExampleType
{
public string ID;
public string name;
//etc.
//Some other members..
}
Now, how would I go through the List example, and query only ExampleType objects that has the name e.g. Peter and store it in another List, like:
List<ExampleType> peterExamples = example. //some query functionality that I can't find
I have tried example.AsQueryable. But couldn't get it to work. I suspect I need some LINQ to query the list maybe?

You can get all ExampleType elements with name == "Peter" like this:
var peterExamples = example.Where(e => e.name == "Peter");
That will return an IEnumerable, if you need a List you can convert it to one by calling ToList().
var peterList = peterExamples.ToList();

This will do the trick
var peterList = example.Where(x => x.name == "Peter").ToList();
In this case the list is only of ExampleType hence no query for only ExampleType is needed. If you were faced with a List<object> though and needed to only run this on ExampleType then you could do the following
var peterList = example
.OfType<ExampleType>()
.Where(x => x.name == "Peter")
.ToList();

You can do it like this:
List<ExampleType> peterExamples = example.Where(t=>t.name == "Peter").ToList();
Or you could use query syntax:
List<ExampleType> peterExamples = (
from item in example
where item.name == "peter"
select item ).ToList();

peterExamples.Where(p=>p.name== "Peter").ToList()
peterExamples.Where(p=>p.name.Contains("Peter")).ToList();//to search for LIKE '%Peter%'

LINQ (Enumerable) extension methods can be used on any IEnumerable<T> (IQueryable<T> is a subtype of IEnumerable<T>), which includes List<T>.
If intellisense is "not working", or there are errors such as "Where/AsQueryable not recognized as .. method", then the code needs to import the extension methods (e.g. using System.Linq) so that the are available.
See LINQ (Language-Integrated Query) for further usage and information.

Here is a solution without LINQ using List<T>'s FindAll method:
var peterExamples = example.FindAll(item => item.name == "Peter");

You must also have this using statement for the Linq queries to work.
using System.Linq;

Related

C# Linq .Find() return many results

I am trying to create a simple search function for my application. I am using Linq's .Find() method to search through a list of objects. It all works very well, the only problem I'm currently having is that I only get the first result. I know for a fact that there are more than one results to be had, but I only get one. Here is my code:
case 5: {
//Search for Price
Product searchResult = tempList.Find(x => x.getPrice() == searchPrice);
if (searchResult != null) {
//Present Result
searchTable.Rows.Add(convertIDValue(searchResult.getProductID()), searchResult.getTitle(), searchResult.getYear(), searchResult.getAmount(), searchResult.getPrice());
}
else {
MessageBox.Show("No product with that price", "0 results");
}
break;
}
I thought I could change Product searchResult into List<Product> searchResults in order to get a list of Products, then loop through that list. But that gave me an error saying:
Cannot implicitly convert type '.Product' to 'System.Collections.Generic.List<.Product>
Is there any way to get Linq's .Find() to return multiple results?
Use Where() and ToList() to get all objects, matching the condition into a List
replace
Product searchResult = tempList.Find(x => x.getPrice() == searchPrice);
with
List<Product> searchResult = tempList.Where(x => x.getPrice() == searchPrice).ToList();
There is a FindAll method for that purpose:
List<Product> products = tempList.FindAll(x => x.getPrice() == searchPrice);
Find() searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List.
You need to use FindAll() instead.
Microsoft explains the "Find()" method :"Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List."
I would suggest you to use this Where() method from Linq extension.
Don't forget to import "using System.Linq" in your current class.
Product searchResult =
means you are declaring one element. The thing you need is a collection of products, like:
IEnumerable<product> searchResult =
The easiest way to do it is to change Find() to where():
IEnumerable<product> searchResult = tempList.Where(x => x.getPrice() == searchPrice);
this will create some collection of product's. It will be easier to maintain as a list, so:
list<product> searchResult = tempList.Where(x => x.getPrice() == searchPrice).toList();
Read about IEnumerable interface :)

Return an IQueryable<dynamic> to filter in the parent method

For example, I have this code:
IQueryable<MyModel> q = new List<MyModel>().AsQueryable(); // this is just an example, this is obviously not a list
var query = from item in q select new { item.Property };
var oneItem = query.FirstOrDefault(x => x.SomeProperty == somevalue);
var allItems = query.ToArray();
Now in a bit more complex situation, I need to get oneItem and allItems in two different methods. So to follow DRY, i'd like to move my query to a private method and then in the consuming ones just call this.GetQuery().FirstOrDefault() or .ToArray() as required.
However, when I try to have the method as IQueryable<dynamic> I get the 'An expression tree may not contain a dynamic operation' error. If I change it to IQueryable<object> then my filtering in the oneItem doesn't work.
You need to return
IQueryable<MyObject>
You can make your methods/classes dry by using genrics eg
IQuerable<T> GetQueryable()
Then the consumer can specify what T should be and your away.
You can't use dynamic with linq. See here to understand why.
For two methods to communicate they must understand the same type so you really want to project into a named type.
If you insist on using dynamic programming it can be done but you will need a lot of casting because dynamic is not a type but just a way of treating object:
IQueryable<MyModel> q = new List<MyModel>().AsQueryable(); // this is just an example, this is obviously not a list
IQueryable<object> query = from item in q select (object)new { item.Property };
var oneItem = query.FirstOrDefault(x => ((dynamic)x).SomeProperty == somevalue);
object[] allItems = query.ToArray();

Possible to order a dynamic type?

Say I have the code below:
dynamic myData = GetMyData();
foreach(dynamic d in myData.data)
{
Console.WriteLine(d.name);
}
How could I writeout all of the names in alphabetical order? If I were using something like List<MyClass> i would just use myData.OrderBy(t => t.name), but this does not seem to work when I'm using a dynamic type.
Any suggestions to how I can order these values?
Enumerable.OrderBy(myData, (Func<dynamic, dynamic>)(t => t.name));
That should return the same as myData.OrderBy(t => t.name) would normally.
Since OrderBy is an extension method, it won't work on dynamic types. See this answer.
This might work for you:
IEnumerable<dynamic> sequence = Enumerable.Cast<dynamic>(myData);
foreach (var result in sequence.OrderBy(x => x.name))
{
Console.WriteLine(result.name);
}
Basically after the call to Cast<dynamic> and the conversion to IEnumerable<dynamic>, you can do what you like as a sequence rather than a single value.
Not that I've actually tried the above, but I believe it should work.

Can I generate a linq expression dynamically in C#?

I've currently got a piece of Linq that looks something like this ;
List<dynamic> childrenToBeRemoved = this.ItemsSource.Where(o => o.ParentID == "1234").ToList();
where ItemsSource is an ObservableCollection of dynamics.
This works fine, but the problem I've got is that the ParentID is a property that can vary. E.g. it could be named ParentPkey or ParentKey etc.
Can I create an expression where I can specify the property that I want to use in my comparison?
I've tried using dynamic linq but it doesn't work using a collection of dynamics, works fine with a collection of pocos.
Thanks...
it should not matter if query is dynamic linq or not
Expression<Func<Entity, int>> predicate = x => x.Id == myvalue;
from entity in _context.Entities.Where(predicate)
select entity;
Check out PredicateBuilder of LinkKit # http://www.albahari.com/nutshell/linqkit.aspx
there are enough examples there as well
Responsibility of translation of an expression to corresponding sql lies with the linq provider, so make sure the provider you are using supports the relevant aspects
why make the implementation itself dynamic? you could simply do a dynamic invocation!
IEnumerable<MyItem> result;
if (condition1)
{
result = this.Items.Where(arg => arg.ProductId == "123");
}
else if (condition2)
{
result = this.Items.Where(arg => arg.ProductPK == "123");
}
or
Func<Item, bool> predicate;
if (condition1)
{
predicate = item => item.ProductId == "123";
}
else if (condition2)
{
predicate = item => item.ProductPK == "123";
}
var result = this.Items.Where(predicate);
Sooo ... I believe you should tell us more about your actual problem - I do not see any current need to implement sth - so, I believe your requirement is ill-defined!
Put you linq expression into a function, and pass in this property as a parameter.
If you know the type of your items, you can use reflection :
PropertyInfo parentProp = itemType.GetProperty("ParentKey or whatever");
List<dynamic> childrenToBeRemoved = this.ItemsSource.Where(o => Equals("1234", parentProp.GetValue(o, null))).ToList();

ArrayList C# Contains method query

I have an ObservableCollection<myClass> list. It contains a 10 objects of type MyClass.
class MyClass
{
string name;
int age;
}
If I want to find all items in list where age = 10, can I use the Contains method?
If yes how can I do this without using iteration?
var age10 = list.Where(i => i.age == 10);
Lots more queries here: http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
No, Contains only looks for a specific value, not something matching a predicate. It also only finds one value rather than every matching value.
You can, however, use Where from LINQ to Objects, assuming you're on .NET 3.5 or higher:
foreach (var item in list.Where(x => x.Age == 10))
{
// Do something with item
}
Since ObservableCollection<T> implements Collection<T> which implements IEnumerable<T>...you can use the LINQ to Object extension methods to make this simple (even though it will use iteration in the background):
var results = list.Where(m => m.age == 10);
As others have stated, using .Where(i => i.Age == 10) would be the correct way to get the result stated in the question. You would use .Contains() to check your collection for a specific instance of your class.
You can use linq to do this but not Contains
var foo = from bar in myCollection where bar.age == 10 select bar;

Categories

Resources