What is "further filtering" for iterators?
Asked Answered
B

1

5

I've always preferred to use IEnumerable instead of List, for obvious reasons, where applicable. In the current project, I've bumped into IList and after I've g'ed it, the Internet told me that there's no significant difference between them except for a single property - the support for further filtering.

Since I wasn't certain what that meant in regard to iterators in C#, I g'ed that too. Any possible relevant answer drowns in the gazillions of hits on "supports further filtering" telling me that IEnumerable does it, while IList doesn't.

So I'm asking twosome question here.

  1. What does support for further filtering mean?
  2. How can I google such terms (in a more general sense)?

As it's a general observation based on many posts, I can't list them all here. One example might be this particular link.

Bibliomancy answered 14/8, 2014 at 7:54 Comment(13)
None of the results I get from searching IEnumerable further filtering are very good. It's like someone read something and summarised it badly, and then a lot of other people copied it without really understanding either.Gilli
+1 ... thats a nice question. I thought of deferred execution and something like that. Further filtering in LINQ means something like myList.Take(10) to get Top 10 items in list e.g.Eleneeleni
Is your source for that credible? I highly doubt that IList has an additional filtering abilitySalsala
@Eleneeleni I'm not sure I understand. Are you saying that I can't use e.g. .Where(lambda) and such on my objects typed IList?Bibliomancy
@KonradViltersten no you CAN use it ! and that is also called further filtering. But i dont know if it is THAT further filtering that is mentioned in IEnumerableEleneeleni
@Salsala There are a bunch of posts telling more or less the same. For a fuller list, please see my comment to Rawling above. For a specific example, please follow this link.Bibliomancy
@Eleneeleni I'm suspecting that too. No idea what is meant by this "further filtering", other that what one might expect. Hence the question here. I got no wiser but at least my rep jumped up a bit, hehe.Bibliomancy
@KonradViltersten i think that this further filtering difference Thing is obsolete since LINQ Extensions. You can do everything on everythingEleneeleni
@KonradViltersten: Please include a link to one or more concrete articles telling you what you think you found. Telling readers they can google it themselves is not sufficient as a reference, or else we could simply leave out, for example, the bibliography section at the end of scientific papers, as well. Everyone can just go and find the sources themselves. You claim something, it is you who has to point readers precisely to the source of the information you base that claim on. -1 for a lack of sources.Endocarditis
Not clear at all what is asked. I wonder why people upvoted. An IList<T> (or an IReadOnlyList<out T>) is also, by inheritance, an IEnumerable<out T>, so it "supports" everything the IEnumerable<> supports. "Further filtering" is not clear; to me it sounds like Linq's Where following another Where, but that makes no sense in the context. The only thing IEnumerable<out T> has that List<T> lacks, is the covariance ("out"). Use IReadOnlyList<out T> if you want covariance and access by index.Cordero
@KonradViltersten Did some google research and I think I know what you refer to (although your posted link to Rawling don't show these blog posts on my German google). I think all these posts are copies of one blog post from a Developer. Since this blog post used IList and IEnumerable in each bullet point these posts are listed very high in Google. But that doesnt make them very credible in my eyesSalsala
@JeppeStigNielsen Please explain which of the two questions listed is unclear. Please note that it's not about the differences between those classes.Bibliomancy
Both questions are unclear. There is nothing commonly called "further filtering" (see also Groo's answer), so asking what support for it means, is unclear. Asking how you can Google terms whose semantics are undefined in the context, is unclear. As I said, you might want to look into covariance in generics of C#. If you have a method void RunThroughAnimals(IEnumerable<Animal> animals) { ... }, I can call your method with a list of giraffes, List<Giraffe>, because of covariance. With a method void RunThroughAnimals(IList<Animal> animals) { ... }, I cannot come in with a List<Giraffe>.Cordero
D
8

There is no such thing as "further filtering".

Filtering collections is usually done using the IEnumerable.Where extension method, which is defined for the IEnumerable interface. And since IList inherits from IEnumerable, you can call Where on both interfaces (calling Where on a IList actually calls the IEnumerable.Where extension method). So, in both cases, the same base method is called, and the type of the resulting value will be an IEnumerable (not an IList when applied to a list). This might be the source of confusion ("you cannot filter the IList further since you don't have it anymore?"), but nothing stops you from filtering the resulting IEnumerable<T> again, or even writing your own extension method which would create a new List on each call.

The post linked to in the question is of low quality and shouldn't be trusted.

For detailed explanation, see below.

You can filter elements from both interfaces pretty much the same, although you will generally use IEnumerable extension methods (i.e. LINQ) in both cases, since IList inherits from IEnumerable. And you can chain as many Where statements as you like in both cases:

// `items` is an `IEnumerable<T>`, so we can call the `Where` extension method.
// Each call creates a new instance, and keeps the previous one unmodified.
IEnumerable<T> items = GetEnumerableItems();
var filteredItems = items
    .Where(i => i.Name == "Jane")      // returns a new IEnumerable<T>
    .Where(i => i.Gender == "Female")  // returns a new IEnumerable<T>
    .Where(i => i.Age == 30)           // returns a new IEnumerable<T>

// `list` is an `IList<T>`, which also inherits from `IEnumerable<T>`.
// Calling `Where` on a list will also not modify the original list.
IList<T> list = GetEnumerableItems();
var filteredList = list
    .Where(i => i.Name == "John")      // returns a new IEnumerable<T>
    .Where(i => i.Gender == "Male")    // returns a new IEnumerable<T>
    .Where(i => i.Age == 30)           // returns a new IEnumerable<T>
    .ToList();                         // returns a new List<T> (optional)

Googling for the term returns several articles mentioning it (like this, or this), they all seem to copy the same source, seems like plagiarism without actual reasoning behind it. The only thing that can come to my mind is that applying Where to an IEnumerable<T> returns a new (filtered) IEnumerable<T>, to which you can again apply Where (filter it "further"). But that is really vague, since applying Where to an IList<T> will not prevent you from filtering it, even though the resulting interface is an IEnumerable<T>. As mentioned in comments, it might be worth mentioning that the List<T> class, as a concrete implementation of IList<T>, exposes a FindAll method which returns a new filtered concrete List<T> (and can be "further filtered"), but that's not a part of IList<T>.

The main difference between repeatedly filtering an IEnumerable<T> and filtering a list into a new list (e.g. using FindAll), is that the latter needs to create a new List<T> instance in each step, while IEnumerable<T> uses deferred execution and doesn't take extra memory apart from storing some tiny state information for each Where call. And again, just to avoid confusion, if you call Where on a List<T>, you still get the benefits of IEnumerable<T> laziness.

Actual differences:

IList (or actually IList<T>, which I am presuming you're referring to) represents a collection of objects that can be individually accessed by index. This means that you can efficiently (in O(1) time) get the value of an object at a certain location, as well as list's length. The "bad thing" is (presuming that it's implemented as a List<T> under the hood), that this means that you need to keep the entire collection in memory.

The "only thing" IEnumerable (i.e. its generic counterpart IEnumerable<T>) can do is to iterate over (zero or more) items. It doesn't have a notion of an index (you cannot "jump" to an index, without actually iterating, or skipping, all items before that item). And you also cannot get the length efficiently in the general case, without actually counting items every time. On the other hand, an IEnumerable is lazy-evaluated, meaning that its elements don't have to exist in memory until they are about to be evaluated. It can wrap a database table underneath, with billions of rows, fetched from the disk as you iterate it. It can even be an infinite collection.

Dynamic answered 14/8, 2014 at 8:4 Comment(19)
This seems to answer only half the question. Or rather, none of the questions actually asked in the end, though it correctly points out how further filtering being the only difference between enumerable and list is a misconception to start with.Endocarditis
All you say is true (I'll even consider +1 for the emphasis on typization of the arrays, which I always advocate myself but skipped here with respect to irrelevance, laziness and space). However, it doesn't answer my question at all. I'm asking about "further filtering" not the difference between IEnumerable and IList. The difference is (very briefly) stated in the question already.Bibliomancy
@S.L.: The OP wrote "the Internet told me that there's no significant difference between them except for a single property - the support for further filtering". Neither is that the only difference, nor is it true in the first place, at least if the further filtering does refer to the extension methods for enumerables, as I suspect.Endocarditis
I am not sure why my answer is taken as "not useful". This is the only distinction between these interfaces. There is no such thing as "further filtering". You can "filter" both IEnumerable and IList forever if you like. This is one of the articles on that subject, but I don't see any logic in that sentence.Dynamic
@O.R.Mapper I'm asking about "further filtering" not the difference between IEnumerable and IList. The difference is (very briefly) stated in the question alreadyEleneeleni
@S.L.: Please read the question, and you will see that only one difference is stated there. That difference is incorrect, and there are actually other differences, which are listed in this answer.Endocarditis
@O.R.Mapper I googled "difference ienumerable ilist" and a bunch of very similar posts popped out. If these are incorrect (can't we trust everything on the Internet?! WHAT?!), please kindly point me to a reliable source for a comprehensive list of differences. Also, still I'm wondering about the meaning of "further filtering". Could it refer to something else that we think spontaneously and intuitively?Bibliomancy
@Groo I saw your edit (it's +1 in a second). Can you offer an explanation to what a number of blogs refer to by "further filtering", please? Just google the term I mentioned and see what you get. Not saying it's correct just because they're many. I'm just wondering where that came from.Bibliomancy
@Konrad: yes, I've found articles like this and this, they all seem to copy the same source, just plagiarism. The only thing that can come to my mind is that applying Where to an IEnumerable<T> returns a new IEnumerable<T>, to which you can again apply Where. But that is really vague, since applying Where to a IList<T> will not prevent you from filtering it, even though the resulting interface is an IEnumerable<T>.Dynamic
@O.R.Mapper i understand that the op knows what he is doing and knows the differences. You are right that he didnt Point out it in the question :) Now the answer is good and i give a +Eleneeleni
Oh, that must be it. Plagiarism = pure idiocy. As for the explanation, I think you're right, mate. IEnum spits out type-alike thingy, while IList doesn't, hence one can't filter it at all, not only furtherly. Stupid formulation! I'd like you to put in the contents of your last comment as the first paragraph in your reply (answer to #1). In the currently first you might mention that it's not possible to google this particular term as it doesn't exists (answer to #2). Then, I'll be delighted to mark it as the correct answer.Bibliomancy
You can use List<>.FindAll method to "filter" a List<> into a new instance of List<>. But prefer Linq most of the time. FindAll is just like Where.Cordero
@KonradViltersten the LINQ Extension method are all for IEnumerable<T> maybe thats the cause for IList<T> you get an IEnumarable<T> and a method ToList()exists :) And ToList()is not deferred executed, it is some of kind finalEleneeleni
@Jeppe: That's true, although it's as a concrete List<T> method, not a member of the interface. But even this returns a new List<T> which "supports further filtering", so it really doesn't make sense.Dynamic
I took the liberty to add something to your answer. Is that OK? Please review my edit and change according to your liking.Bibliomancy
@Konrad: thanks, I would only rephrase the "IList type switches its type to IEnumerable" a bit, because the type of the returned value is actually IEnumerable (original list is not "modified" by calling Where). If would be more precise to say that IList inherits from IEnumerable, and gets all its extension methods along - so the Where method is the one and only method used in both cases, and it returns an IEnumerable.Dynamic
Do that. Agreed. Just keep in mind that a rookie totally confused will be even more confused when we start with inheritance and such. That's why I love how it's split into short-and-blunt and a long-and-elaborative part now.Bibliomancy
@Konrad: I agree completely, I just didn't want the answer to imply that the original list is somehow modified or changes its own type. I'd like to simplify it as much as possible, but not lose correctness: the same base interface's method (Where) is called in both cases, it acts like it's operating on IEnumerable in both cases, and returns a new IEnumerable in both cases.Dynamic
Oh, that's a very nice and clear answer. I'd bounty you if I wouldn't be a stingy reputation junkie, haha. You have my moral bounty granted, though.Bibliomancy

© 2022 - 2024 — McMap. All rights reserved.