0

For example, I Have such code:

IEnumerable<RSuspectOperationCode> distinctCodes = this.Distinct(); // "this" is some collection
this.Clear()
distinctCodes.Count();

As LINQ is deferred execution query - Count gives us 0. I'm interesting - is there a approach to get a distinct collection with in-place result calculation and breaking link between source and result collection, that clearing source collection won't affect result collection?

My workaround:

    List<RSuspectOperationCode> distinctCodes = new List<RSuspectOperationCode>();
    distinctCodes.AddRange(this.Distinct(comparer));
    this.Clear();
    distinctCodes.Count();

But, I wonder, is there more elegant/shorter way?

Andrey Khataev
  • 1,303
  • 6
  • 20
  • 46

4 Answers4

1

call .ToList() whenever you want it to be executed immediately.

var distinctCodes= this.Distinct().ToList();

this.Clear();

var c1 = this.Count(); // 0

var c2 = distinctCodes.Count(); // eg. 100
Vland
  • 4,151
  • 2
  • 32
  • 43
  • This won't have deferred execution for distinct. – brz Aug 31 '14 at 07:58
  • @user3246354 He didn't ask for deferred execution on his distinct list. He just wants a list of distinct items. – Vland Aug 31 '14 at 11:32
  • I was refering to in-place result calculation in "is there a approach to get a distinct collection with in-place result calculation and breaking link between source and result collection, that clearing source collection won't affect result collection?" – brz Aug 31 '14 at 11:34
1

Instead of calling ToList after Distinct, call it before so you have deferred execution in your distinct list:

var distinctCodes = this.ToList().Distinct();
brz
  • 5,926
  • 1
  • 18
  • 18
0

I use to add .ToList() at the end of a Linq expression to get the enumeratio done, and to have a copy of the collection.

In your case,

... = this.Distinct().ToList()

should do the trick.

Larry
  • 17,605
  • 9
  • 77
  • 106
0

You need to call some method that will evaluate the query. In your case, calling ToArray or ToList will do what you want by evaluating the query and placing the result in a new array or List<RSuspectOperationCode>. That new list will not be affected by any changes you make to the original list.

Note that a lot of people use ToList by default, which is wrong. Regardless of the situation, if you don't intend the change the length of a list then you should use an array rather than a collection. That means that ToArray should be your default choice and only use ToList when you specifically need a List<T>. It's not a major issue but you may as well do things the right way.

jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
  • 3
    *That means that ToArray should be your default choice* I believe `ToArray` can end up with an extra memory allocation than ToList, because an array has to be the exact size of the collection it represents whereas a List separates its capacity from its size. http://stackoverflow.com/a/16323412/242520 – ta.speot.is Aug 31 '14 at 07:48
  • 1
    Yes, I know how `List` is implemented. `ToList` and `ToArray` both follow the same allocation pattern up until the very end, in which case `ToList` is done but if `ToArray` has allocated an array that's bigger than necessary it has to allocate *another* array of the correct size and copy everything into it. So by using `ToList` you skip that overhead. – ta.speot.is Aug 31 '14 at 07:52