IEnumerable<T> VS IList<T> VS IQueryable<T> - c#

New to the MVC.net scene (and .net for that matter), but seems I find a wide array of options when wanting to populate a "list" with data. In my case at the moment, I'd like to populate a list from a select query of items and render the results in JSON for output, so bear with me....
So, my viewmodel class is something like :
[Serializable()]
public class TFSquery
{
public int MsgUid { get; set; }
public DateTime CreateStamp { get; set; }
}
And then I'd like to populate it with my query output:
List<TFSquery> z = (from msg in _DB.Msg
select new { msg.MsgUID, msg.CreateStamp }).ToList();
Then would I loop the output into my List so that I can then output in my Json return string? And when I use a LIST VS IENUMERABLE VS IQUERYABLE??
return Json(new { Result = z }, JsonRequestBehavior.AllowGet);

My rules of thumb:
Use a List when you have to add, remove, or refer to an item by index.
Use a IQueryable when you have to run ad-hoc queries against it.
Use IEnumerable by default.
It looks like you're already doing the query "in" your database, so I'd suggest using the simplest version: IEnumerable to simply be able to loop through the results.

If your new to .NET and C# I'd spend some time researching and becoming knowledgeable about what the different collection types are, how they differ, and when to use them. You'll use collections so often it you cannot afford to have a "simple one liner" summary understanding like the other answerers posted.
Here is a good guide on .NET collection types:
http://msdn.microsoft.com/en-us/library/0ytkdh4s.aspx
IQueryable is its own special beast and deserves its own guide:
http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

Each interface has its own set of uses.
IQueryable is for deferred queries (that is, it saves the query but only executes it when it is enumerated)
IEnumerable can be enumerated and that's it.
IList can have items added and removed.

Related

Is there anything like RegEx, but for structured objects?

I feel like what I'm looking for should exist, but I don't know what it's called. All searches for "regex for objects" just return tutorials and questions about normal RegEx. Searches for "pattern matching" return news about C# 7's new pattern matching feature, which isn't what I'm trying to accomplish.
To illustrate what I'm after, assume you have the following class:
public class Car
{
public string Color { get; set; }
public int MilesDriven { get; set; }
public bool IsAllWheelDrive { get; set; }
}
And then assume you have a List of Car objects with random and varied properties. I'd like to be able to search through the list for RegEx-like patterns and get the beginning and ending indexes of each instance the pattern occurs.
Example patterns would be:
Find all instances where a white car with all wheel drive occurs between 2 blue cars and the first blue car has more than 1000 miles on it.
Find all instances where a red car is immediately followed by at least 2 green cars and eventually is followed by a car with less than 100 miles on it.
This is a bit of a contrived question, but I would like to know if anything like this exists, preferably as an existing C# library.
Apologies if "pattern-matching" isn't an applicable tag for this question, but as I stated, I don't really know what, if anything else, to call this.
What you are looking for is the filter concept. C# does provide an application of such a concept for lists, however it gets complicated if you aren't just trying to filter on the attributes of the object. Microsoft makes the filitering capability generic accross C# with LINQ See this post, or this post for an example:
Filtering collections in C#
Basically the syntax is :
var newlist = list.linqquery1.linquery2...linqueryN.Where(s.x condition);
of course if its simple enough you can do the following:
var newlist = list.Where(s.x condition);
But your problem also calls for selection based on subsequent items in the list. This is a whole lot more complicated because you won't be able to access those elements unless you attach that data to the element in the list. For example, if your listelem was actually a doubly linked list node, you could look ahead in the list for elements after ward based only on a forward node reference and run a condition like this (to check if two green cars follow):
var green2follows = carlist.Where(s.next.type == greencar && s.next.next.type == greencar);
You could, however, concieve of a situation in which it wouldn't be necesary to use doubly linked lists if you implimented this yourself with iteration. Unfortunately, because LINQ works primarily on enumeration based queries, you have to find work around to use Microsofts built in utilities for filtering (though this is not unique to microsoft, typically you don't include locality in queries) This post covers that conclusion.
To do this iteratively, you would create a for loop and test against i + 1, and i + 2 values of cars. Be carful as this gets messy with previous values (i - n) Iterators might be good for this to avoid errors, though i'm not sure if c# supports iterator arithmetic like other languages to allow you to go backwards and forwards. You may be forced to make a custom iterator to generically define this kind of filter.
EDIT: you can avoid creating a custom iterator and merely create a custom object returned by the iterator that supports forward and backward looking via iterator blocks (like the answer suggest in this post)
What you might do is something like this:
HandleObject<T>...
...
public bool backwardsWhere(condition)...
public bool forwardsWhere(condition)...
public bool backwardsNWhere(n, condition);
public bool forwardsNWhere(condition);
//other forwards filter functions for convienience
// get back the element that we wraped
public T get();
static IEnumerable<T> iteratorBlock(List<T> list)
{
foreach (int i = 0; i < list.Length; i++)
{
// yield means a new HandleObject is only created upon access, and
// need not be stored otherwise
yield return HandleObject<T>(i, list);
}
}
Instead of using your list and LINQing over that, use this iterator instead templated on your list, this way you don't have to deal with nasty iterator semantics in C# for creating your own whilist still being able to implement all the functionality you would need to go over the list.
var customIterableFromBlock = iteratorBlock<Car>(carlist);
var selectedCars = from handleCar in customIterableFromBlock
where ... //handleCar.backwardsWhere(...)&& handleCar.forwardsWhere(...)
//handleCar.get().x == condition etc
select Car
{
//get Car from handleCar.get()
};
The reason you would include i and the list itself in the HandleObject constructor is to allow for forward and backward searching through the list based on the position i passed in.

Creating a join Linq query to optimize looping together two lists

I'm not good at databases and T-sql queries so I got a little stumped over how to do something similar in C# using Linq.
Thing is I have this structure that is pretty much the same as a relational database table, with which I have to do some kind of join selection.
In effect I get a list of composite key addresses. These are actually classes that hold a few int values (byte or short perhaps but not relevant). Now I have to search through my structure for matches of these lists and call a method there.
This is probably a simple join (can't remember what join does what) but I need some help because I wan't this to be as cheap as I can easily get away with so I don't need to search through every line for every address.
public class TheLocationThing
{
int ColumnID;
int ColumnGroupId;
int RowID;
}
public class TheCellThing
{
TheLocationThing thing;
public void MethodINeedToCallIfInList()
{
//here something happens
}
}
public class TheRowThing
{
int RowId;
List<TheCellThing> CellsInThisRow;
}
public class TableThing
{
List<TheRowThing> RowsInThisTable;
}
So I have this tablething type class that has rows and they have cells. Notice that ColumnGroup thing, it's a composite key with ColumnId so the same columnid can come again but only once for each ColumnGroup.
The thing to keep in mind though is that inn TheTable there will only ever be one GroupColumnId, but the list given could have multiple, so we can filter them away.
public void DoThisThing()
{
List<TheLocationThing> TheAddressesINeedToFind = GetTheseAddresses(); //actualy is a TheLocationThing[] if that matters
var filterList = TheAddressesINeedToFind.Where(a => a.ColumnGroupId == this.CurrentActiveGroup);
//Here I have to do the join with this.TableInstance
}
Now, I should of course only loop through the addresses with the same row id in that row and all that.
Also is managing thing as IQueryable something that would help me out here, especially in the initial filter out, should i get it as Queryable?
I'm going to give different example, because I'm not quite following yours, and use it to explain the basics of joining, hopefully hitting what you need to learn.
Let's imagine two slightly more meaninfully-named classes than LocationThing etc. (which has me lost).
public class Language
{
string Code{get;set;}
string EnglishName{get;set;}
string NativeName{get;set;}
}
public class Document
{
public int ID{get; private set;}//no public set as it corresponds to an automatically-set column
public string LanguageCode{get;set;}
public string Title{get;set;}
public string Text{get;set;}
}
Now, let's also imagine we have methods GetLanguages() and GetDocuments() that return all languages and documents respectively. There's a few different ways that could work, and I'll get to that later.
An example of a join being useful, is if we e.g. wanted all the titles and all the English names of the languages they were in. For that in SQL we would use:
SELECT documents.title, languages.englishName
FROM languages JOIN documents
ON languages.code = documents.languageCode
Or leaving out table names where doing so doesn't make column-names ambiguous:
SELECT title, englishName
FROM languages JOIN documents
ON code = languageCode
Each of these will, for each row in documents, match them up with the corresponding row in languages, and return the title and English name of the combined row (if there's a document with no matching language, it doesn't get returned, if there's two languages with the same code - should be prevented by the db in this case though - corresponding documents get mentioned once for each).
The LINQ equivalent is:
from l in GetLanguages()
join d in GetDocuments()
on l.Code equals d.LanguageCode //note l must come before d
select new{d.Title, l.EnglishName}
This will similarly match each document with its corresponding language and return an IQueryable<T> or IEnumerable<T> (depending on the source enumerations/queryables) where T is an anonymous object with Title and EnglishName properties.
Now, as to the expense of this. This depends primarily on the nature of GetLanguages() and GetDocuments().
No matter what the source, this is inherently a matter of searching through every one of the results of those two methods - that's just the nature of the operation. However, the most efficient way of doing this, is still something that varies according to what we know about the source data. Let's consider a Linq2Objects form first. There's lots of ways that this could be done, but lets imagine they're returning Lists that were pre-computed:
public List<Document> GetDocuments()
{
return _precomputedDocs;
}
public List<Language> GetLanguages()
{
return _precomputedLangs;
}
Let's pretend Linq's join doesn't exist for a moment, and imagine how we'd write something functionally equivalent to the code above. We might arrive at something like:
var langLookup = GetLanguages().ToLookup(l => l.Code);
foreach(var doc in GetDocuments())
foreach(var lang in langLookup[doc.LanguageCode])
yield return new{doc.Title, lang.EnglishName};
This is a reasonable general case. We can go one step further, and reduce storage, since we know that all we finally care about with each language is the English name:
var langLookup = GetLanguages().ToLookup(l => l.Code, l => l.EnglishName);
foreach(var doc in GetDocuments())
foreach(var englishName in langLookup[doc.LanguageCode])
yield return new{doc.Title, EnglishName = englishName};
That's about as much as we can do without special knowledge of the set of data.
If we did have special knowledge, we could go further. For example, if we knew there was only one language per code, then the following would be faster:
var langLookup = GetLanguages().ToDictionary(l => l.Code, l => l.EnglishName);
string englishName;
foreach(var doc in GetDocuments())
if(langLookup.TryGetValue(doc.LanguageCode, out englishName))
yield return new{doc.Title, EnglishName = englishName};
If we knew the two sources were both sorted by language code, we could go further still and spin through them both at the same time, yielding matches, and throwing away languages once we've dealt with them, as we're never going to need it again for the rest of the enumeration.
But, Linq does not have that special knowledge when just looking at two lists. For all it knows every single language and every single document all have the same codes. It really has to examine the lot to find out. For that, it's pretty efficient in how it does it (a bit better than my example above suggests, due to some optimisation).
Let's consider a Linq2SQL case, and note that Entity Framework and other ways of using Linq directly on databases would be comparable. Let's say all of this is happening in the context of a class that has a _ctx member that's a DataContext. Then our source methods could be:
public Table<Document> GetDocuments()
{
return _ctx.GetTable<Document>();
}
public Table<Language> GetLanguages()
{
return _ctx.GetTable<Languages>();
}
Table<T> implements IQueryable<T> along with some other methods. Here, instead of joining things in memory, it'll execute the following (bar some aliases) SQL:
SELECT documents.title, languages.englishName
FROM languages JOIN documents
ON languages.code = documents.languageCode
Look familiar? It's the same SQL we mentioned at the beginning.
First great thing about this, is that it's not bringing back anything from the database that we won't use.
Second great thing, is that the database's query engine (what turns this into executable code that it then runs) does have knowledge of the nature of the data. If for example we've set up the Languages table to have a unique key or constraint on the code column, the engine knows there can't be two languages with the same code, so it can perform the equivalent of the optimisation we mentioned above where we used a Dictionary instead of a ILookup.
Third great thing, is that if we have indices on languages.code and documents.languageCode then the query engine will use these for even faster retrieval and matching, perhaps getting all it needs from the index without hitting the table, making a call as to which table to hit first to avoid testing irrelevant rows in the second, and so on.
Fourth great thing, is that RDBMSs have benefited from several decades of research into how to make this sort of retrieval as fast as possible, so we've stuff going on that I don't know about and don't need to know about to benefit from.
In all then, we want to run our queries against the datasource directly, not against sources in memory. There are exceptions, particularly some forms of grouping (hitting the DB directly with some group-by operations can mean hitting it repeatedly) and if we reuse the same results over and over in quick succession (in which case we're better off hitting it once for those results, and then storing them).

Comparison operators not supported for type IList when Paging data in Linq to Sql

I can understand what the error is saying - it can't compare a list. Not a problem, other than the fact that I don't know how to not have it compare a list when I want to page through a model with a list as a property.
My Model:
Event : IEvent
int Id
string Title
// Other stuff..
LazyList<EventDate> Dates // The "problem" property
Method which pages the data (truncated):
public JsonResult JsonEventList(int skip, int take) {
var query = _eventService.GetEvents();
// Do some filtering, then page data..
query = query.Skip(skip).Take(take);
return Json(query.ToArray());
}
As I said, the above is truncated quite a bit, leaving only the main point of the function: filter, page and return JSON'd data.
The exception occurs when I enumerate (.ToArray()). The Event object is really only used to list the common objects of all the event types (Meetings, Birthdays, etc - for example). It still implements IEvent like the other types, so I can't just remove the LazyList<EventDate> Dates property unless I no longer implement IEvent
Anyway, is there a way to avoid this? I don't really want to compare a LazyList when I page, but I do not know how to resolve this issue.
Thank you in advance! :)
Do a transform on the data before returning it as JSON if you don't want the list e.g.
return Json(query.Select(event => new { event.Id, event.Title }).ToArray());
Try doing an explicit ordering before Skip and Take.

Sorting an List<> with my custom order which is stored in another List (C#)?

Can anyone help.. I have a generic list like so
IList<itemTp> itemTps;
itemTp basically is a class (has a number of properties) and one property on this is "code"
I need to be able to sort it an specific order which i have set in another List.
This list is a simple list that lists the order (starting from first to last) like say
code1
code3
code2
code5
(notice it goes from 1 to 3 to 2 to 5 - these are the names, they can be called anything .. the important thing is the order, it doesn't have anything to do with the numbers)
Basically i need ensure the items in itemTp sort according what is present in the other list...
So imagine my Ilist is like this code1,code2,code3,code5 - so once the sort is done
in my
IList<itemTp>
will contain 4 classes that are in order and have the property like code1,code3,code2,code5 (order change)
Any ideas how to do this?
You'll need to create an IComparer that will compare items based on the state of your other list. The advantage of using an IComparer is that you'll be able to build caching logic into your class to avoid repeated IndexOf() lookups if you need that optimization. Also, you'll be able to maintain multiple "other" lists that can be used when appropriate.
class ItemTpComparer : IComparer<itemTp>
{
private IList<codeTp> otherList;
public ItemTpComparer(IList<codeTp> otherList)
{
this.otherList = otherList;
}
public int Compare(itemTp a, itemTp b)
{
return otherList.IndexOf(a.Code) - otherList.IndexOf(b.Code);
}
}
And to perform the sort:
myList.Sort(new ItemTpComparer(otherList));
Sorry if something is wrong, I don't have a C# editor installed here, but it's something like this:
Array.Sort(
itemTps,
delegate(ItemTp a, ItemTp b)
{
return secondList.IndexOf(a.Code) - secondList.IndexOf(b.Code);
});
Note: it may not be the most efficient way, and also there is no checking whether the second list contains the Code at all.
[Edit] As Mehrdad said, Array.Sort doesn't work for generic IList<T>. To sort the array in place, you would need to use the ArrayList.Adapter method to create a wrapper, and then sort it. Since ArrayList.Sort doesn't support a delegate comparison, you need to put the anonymous delegate inside an implementation of IComparer<T>, .
If you need to sort it in a separate list, then it could have sense to use the logic above by creating an array first.
Using C# 3 and LINQ to Objects, I would just create a new list instead of trying to sort the existing one:
void Example()
{
IList<string> codes;
IList<ItemTp> itemTps;
itemTps = codes.Select(code => itemTps.Single(itp => itp.Code == code)).ToList();
}

Sorting a composite collection

So WPF doesn't support standard sorting or filtering behavior for views of CompositeCollections, so what would be a best practice for solving this problem.
There are two or more object collections of different types. You want to combine them into a single sortable and filterable collection (withing having to manually implement sort or filter).
One of the approaches I've considered is to create a new object collection with only a few core properties, including the ones that I would want the collection sorted on, and an object instance of each type.
class MyCompositeObject
{
enum ObjectType;
DateTime CreatedDate;
string SomeAttribute;
myObjectType1 Obj1;
myObjectType2 Obj2;
{
class MyCompositeObjects : List<MyCompositeObject> { }
And then loop through my two object collections to build the new composite collection. Obviously this is a bit of a brute force method, but it would work. I'd get all the default view sorting and filtering behavior on my new composite object collection, and I'd be able to put a data template on it to display my list items properly depending on which type is actually stored in that composite item.
What suggestions are there for doing this in a more elegant way?
I'm not yet very familiar with WPF but I see this as a question about sorting and filtering List<T> collections.
(withing having to manually implement sort or filter)
Would you reconsider implementing your own sort or filter functions? In my experience it is easy to use. The examples below use an anonymous delegate but you could easily define your own method or a class to implement a complex sort or filter. Such a class could even have properties to configure and change the sort and filter dynamically.
Use List<T>.Sort(Comparison<T> comparison) with your custom compare function:
// Sort according to the value of SomeAttribute
List<MyCompositeObject> myList = ...;
myList.Sort(delegate(MyCompositeObject a, MyCompositeObject b)
{
// return -1 if a < b
// return 0 if a == b
// return 1 if a > b
return a.SomeAttribute.CompareTo(b.SomeAttribute);
};
A similar approach for getting a sub-collection of items from the list.
Use List<T>.FindAll(Predicate<T> match) with your custom filter function:
// Select all objects where myObjectType1 and myObjectType2 are not null
myList.FindAll(delegate(MyCompositeObject a)
{
// return true to include 'a' in the sub-collection
return (a.myObjectType1 != null) && (a.myObjectType2 != null);
}
"Brute force" method you mention is actually ideal solution. Mind you, all objects are in RAM, there is no I/O bottleneck, so you can pretty much sort and filter millions of objects in less than a second on any modern computer.
The most elegant way to work with collections is System.Linq namespace in .NET 3.5
Thanks - I also considered LINQ to
objects, but my concern there is loss
of flexibility for typed data
templates, which I need to display the
objects in my list.
If you can't predict at this moment how people will sort and filter your object collection, then you should look at System.Linq.Expressions namespace to build your lambda expressions on demand during runtime (first you let user to build expression, then compile, run and at the end you use reflection namespace to enumerate through results). It's more tricky to wrap your head around it but invaluable feature, probably (to me definitively) even more ground-breaking feature than LINQ itself.
Update: I found a much more elegant solution:
class MyCompositeObject
{
DateTime CreatedDate;
string SomeAttribute;
Object Obj1;
{
class MyCompositeObjects : List<MyCompositeObject> { }
I found that due to reflection, the specific type stored in Obj1 is resolved at runtime and the type specific DataTemplate is applied as expected!

Categories

Resources