-1

When I want to get an IEnumerable to eagrly materialize/yield all its results I usually use ToList() like this:

var myList= new List<int>();
IEnumerable<int> myXs = myList.Select(item => item.x).ToList();

I do this usually when locking a method returning the result of a Linq query.

In these kind of cases I am not actually interested in the collection becoming a list and I often don't want to know it's type. I am just using ToList() for it's side effect - yielding all the elements.

If for example if I will change the type from List to Array I will also have to remember to change the ToList() to ToArray() or suffer some performance hit.

I can do foreach( var e in myList ) { } but I am not sure if this will be optimized at some point ?

I am looking for something like myList.Select(item => item.x).yield()

What is the best way to do it ? is there a way to simply tell an a Linq result to yield all its elements which is better than ToList ?

kofifus
  • 17,260
  • 17
  • 99
  • 173
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/186034/discussion-on-question-by-kofifus-linq-yield-all-elements). – Bhargav Rao Jan 02 '19 at 09:54

2 Answers2

3

If the point is just to exercise the list, and don't want to construct or allocate an array of any kind, you can use Last(), which will simply iterate over all the elements until it gets to the last one (see source).

If you are actually interested in the results, in most cases you should simply use ToList() and don't overthink it.

There is no way to avoid allocating some sort of storage if you want to retrieve the results later. There is no magic IEnumerable<T> container that has no concrete type; you have to choose one, and ToList() is the most obvious choice with low overhead.

Don't forget ToListAsync() if you'd rather not wait for it to finish.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • That's the correct answer to the question as is, but I wonder what the *actual* question behind that question is. Lazy evaluation perhaps? A casting problem while trying to use the results? Or maybe the source *isn't* a list but an EF, OData entity or SharePoint list? Or could it be that *those* results are mixed with the results of a another query ? – Panagiotis Kanavos Jan 02 '19 at 08:44
  • Thanks! Last will not do as I need the results – kofifus Jan 02 '19 at 08:44
  • @kofifus "There is no way to avoid allocating some sort of storage if you want to retrieve the results later" is the answer (as asked). If you are still not satisfied that the part that you need to explain in the questions how you plan to avoid. – Alexei Levenkov Jan 02 '19 at 09:01
  • John Wu - though you seem to be the only one that understood my question ! :( basically I need a Last() that will return the enumerable its running on – kofifus Jan 02 '19 at 09:02
  • 4
    There is no such thing kofifus. Iterating over the data source destroys it because the underlying database connection is exposed as a forward-only cursor. If you don't cache it the first time around, it's gone. The best you can do is `ToList()` like the rest of us. – John Wu Jan 02 '19 at 09:12
0

Just a FYI, since maybe that is the issue

You don't have to write LINQ Operations in a one-liner you can extend it further and further:

For example:

var myList = new List<T>();
var result = myList.Select(x => x.Foo).Where(x => x.City == "Vienna").Where(x => x.Big == true).ToList();

Could be re-written to:

var myList = new List<T>();

//get an IEnumerable<Foo>
var foos = myList.Select(x => x.Foo);

//get an IEnumerable<Foo> which is filtered by the City Vienna
var foosByCity = foos.Where(x => x.City == "Vienna");

//get an IEnumerable<Foo> which is futher filtered by Big == true
var foosByCityByBig = foosByCity.Where(x => x.Big == true);

//now you could call to list on the last IEnumerable, but you dont have to
var result = foosByCityByBig.ToList();

So what-ever your real-goal is, maybe you can change your line

var myList= new List<int>();
IEnumerable<int> myXs = myList.Select(item => item.x).ToList();

To this:

var myList= new List<int>();
IEnumerable<int> myXs = myList.Select(item => item.x);

And continue your work with myXs as an IEnumerable<int>.

Rand Random
  • 7,300
  • 10
  • 40
  • 88