Linq,使用ToLookup将值投影到不同的命名变量

时间:2010-10-10 09:32:03

标签: c# linq

var tmpProjection = myCollection.ToLookup(t => t.SomeBoolValue);
var listOneFinal = tmpProjection[true];
var listTwo = tmpProjection[false];

第一个问题,有没有办法以较短的方式将它分配给listOne和listTwo,我知道我在这里迂腐,......只是问。

现在,

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

所以在这种情况下,我只需要(最终)listOneFinal,listFourFinal和listFiveFinal - 但我正在创建这些临时内容......有没有办法减少这种情况。

我只是谈论代码而不是性能或代码的关键性。

4 个答案:

答案 0 :(得分:3)

bool对于沟通意图有点弱。 Int有点好,枚举最好。

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];

答案 1 :(得分:1)

您可以在较少的语句中执行此操作,但由于您需要使用3个值结束操作,因此至少需要3个分配。您的代码非常易读,不会牺牲“智能”的可读性并减少更少的语句。话虽这么说,这是一个3语句版本;如果集合很小(在大型集合中你自己的版本会表现得更好,因为这个版本在集合中多次迭代),这将很有效:

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);

根据您的实际使用情况,上述内容可能更具可读性。

答案 2 :(得分:0)

我认为你所拥有的东西已经非常好了,说实话。

如果您只想减少语句的数量,我怀疑您可以做得更好:

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);

或者也许:

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));

(如果需要,请在每个查询上调用ToList()

但实际上,我更喜欢你的技术,我提供的代码不是特别易读有效。

您可能想要考虑仅存储2个查找而不是每个列表,并在必要时内联每个“最终查找”,因为调用Lookup[key]很便宜。因此,只要您需要listFourFinal,只需调用listThree[false].更好的变量名称显然会有所帮助。

答案 3 :(得分:0)

如果您发现自己经常这样做,可以编写一个函数来执行此操作。对于布尔值ToLookup,我们可以使用C#的out parameters来返回多个值。

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();
}

现在我们可以做到:

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