开发者

Linq, using ToLookup to project values to different named variables

开发者 https://www.devze.com 2023-01-19 15:03 出处:网络
var tmpProjection = myCollection.ToLookup(t => t.SomeBoolValue); var listOneFinal = tmpProjection[true];
var tmpProjection = myCollection.ToLookup(t => t.SomeBoolValue);
var listOneFinal = tmpProjection[true];
var listTwo = tmpProjection[false];

First question, is there a way to assign it to listOne and listTwo in some shorter way, I know I'm being pedantic here, ... just asking.

Now,

var listThree = listTwo.ToLookup(t => t.SomeOtherBoolValue);
var listFourFinal = listThree[false];
var listFiveFinal = listThree[true];

So in thise case, I just need (ultimately) listOneFinal, listFourFinal and listFiveFinal -- but i'm creating thi开发者_JAVA百科s temp stuff in between ... is there a way to reduce this.

i'm only talk code-wise not performance or code criticality.


bool is kind of weak for communicating intent. Int is a little better and enum would be best.

Lookup<int, T> myLookup = myCollection
.ToLookup(t =>
  t.someBoolValue ? 1 :
  t.someOtherBoolValue ? 4 :
  5
);

var listOne = myLookup[1];
var listFour = myLookup[4];
var listFive = myLookup[5];


You can do it in fewer statements, but since you need to end op with 3 values, you need at least 3 assignments. Your code is very readable, don't sacrifice readability for "being smart" and reducing to fewer statements. That being said, here is a 3 - statement version; that will work well if collections are small (your own version will perform better with larger collections, since this version iterates multiple times through the collection):

var listOneFinal = myCollection.Where(t => t.SomeBoolValue);
var listFourFinal = myCollection.Where(t => !t.SomeBoolValue && !t.SomeOtherBoolValue);
var listFiveFinal = myCollection.Where(t => !t.SomeBoolValue && t.SomeOtherBoolValue);

Depending on your real usage scenario, the above might be more readable.


I think what you've got there is pretty good already, to be honest.

If you're simply looking to minimize the number of statements, I doubt you could do better than:

var listOneFinal = myCollection.Where(t => t.SomeBoolValue);
var listFourFinal = myCollection.Where(t => !t.SomeBoolValue && !t.SomeOtherBoolValue);
var listFiveFinal = myCollection.Where(t => !t.SomeBoolValue && t.SomeOtherBoolValue);

Or perhaps:

var predicates = new Func<MyClass,bool>[]{ t => t.SomeBoolValue, t => t.SomeOtherBoolValue};
var listOneFinal = myCollection.Where(predicates.First());
var listFourFinal = myCollection.Where(t => !predicates.Any(p => p(t)));
var listFiveFinal = myCollection.Where(t => !predicates[0](t) && predicates[1](t));

(Call ToList() on each query if desired)

But really, I prefer your technique much better, the code I have provided is not particularly more readable or efficient.

You might want to consider just storing the 2 lookups instead of each list and inline each 'final lookup' where necessary since it's cheap to call Lookup[key]. So whenever you need listFourFinal, just call listThree[false]. Better variable names would help, obviously.


If you find yourself doing this often, you can write a function to do it. For a boolean ToLookup, we can use C#'s out parameters to return multiple values.

public static void Dichotomize<T>(this IEnumerable<T> source,
                                  Func<T,bool> keySelector,
                                  out IEnumerable<T> affirmative,
                                  out IEnumerable<T> negative) {
    if (source == null) throw new ArgumentNullException("source");
    if (keySelector == null) throw new ArgumentNullException("keySelector");

    var affirmativeList = new List<T>();
    var negativeList = new List<T>();
    foreach (var element in source) {
        (keySelector(element) ? affirmativeList : negativeList).Add(element);
    }
    affirmative = affirmativeList.AsReadOnly();
    negative = negativeList.AsReadOnly();
}

Now we can do:

IEnumerable<T> listOneFinal, listTwo, listFourFinal, listFiveFinal;
myCollection.Dichotomize(t => t.SomeBoolValue, out listOneFinal, out listTwo);
listTwo.Dichotomize(t => t.SomeOtherBoolValue, out listFiveFinal, out listFourFinal);
0

精彩评论

暂无评论...
验证码 换一张
取 消