IEnumerable,其中All满足X并且至少有一个符合y

时间:2011-02-10 02:43:38

标签: .net linq ienumerable iteration

我有2 IEnumerable<decimal>。例如{0,0.1,0.5,1}{a,b,c,d} 假设长度相等

示例域对象代码:

public class Foo //does not implement IEnumerable because nothing outside of itself should treat it as such
{
 private readonly decimal _a;
private readonly decimal _b;
private readonly decimal _c;
//another class also has private readonly  decimal _d;

public decimal A {get{return _a;}}
//...
public decimal C {get{return _c;}}
}

我想定义Foo1>Foo2

  • 如果全部符合>=(如Foo1.A>=Foo2.A && ' .. 'Foo1.C>=Foo2.C ..)
  • 至少一个>(如Foo1.B>Foo2.B

示例迭代代码:

//DRY violation, but probably the shortest route to the goal
private static IEnumerable<Func<Foo,decimal>> Accessors=
 new List{f=>f.A,f=>f.B,f=>f.C};

public static bool operator>(Foo foo1, Foo foo2)
{
  if (foo1==null||foo2==null)
    return false;
  bool foundGreater=false;
  foreach (var accessor in _Accessors)
  {
    if (accessor(foo1)<accessor(foo2))
      return false;
    if (foundGreater==false&&accessor(foo1)>accessor(foo2))
      foundGreater=true;
  }
  return foundGreater;
}
从学习的角度来看,欢迎涉及zip的信息和答案,以及使用不涉及反射的相同比较功能来攻击可变属性长度的整个问题。

但是,我目前正在使用.q 2.0与LinqBridge一起工作。

我正在考虑以下内容来涵盖所有需要相同功能的类

  //Needs a better name for sure
  public static bool AllWithAny<T,TValue>(IEnumerable<Func<T,TValue>> accessors,T item1, T item2,
      Func<TValue,TValue,bool> shortCircuitBreak,Func<TValue,TValue,bool> atLeastOneCondition)
    {

      GuardStrategy.ThrowIfNull(accessors,"accessors");
      GuardStrategy.ThrowIfNull(item1, "item1");
      GuardStrategy.ThrowIfNull(item2, "item2");
      var foundOne=false;
      foreach(var accessor in accessors) 
      {
        var values=new {Value1=accessor(item1),Value2=accessor(item2)};
        if (shortCircuitBreak(values.Value1, values.Value2))
          return false;
        if(foundOne==false && atLeastOneCondition(values.Value1,values.Value2))
         {
          foundOne=true;
         }
      }
      return foundOne;

    }

问题:

是否有现有的Linq关键字/运算符组合可以更优雅地完成所有这些操作? 是否有更优雅/更简单的方法来进行这种类型的比较,即更好的DRY,更少的编码和更多的重用?

2 个答案:

答案 0 :(得分:1)

没有经过测试,但只需稍加修改即可。

public class Foo {
    public decimal A { get; set; }
    public decimal B { get; set; }
    public decimal C { get; set; }

    IEnumerable<decimal> Values {
        get { return new [] { A, B, C }; }
    }

    public static bool operator > (Foo x, Foo y)
    {
        var pairs = x.Values.Zip (y.Values,
            (xv, yv) => Tuple.Create (xv, yv));

        return pairs.All (pair => pair.Item1 >= pair.Item2)
            && pairs.Any (pair => pair.Item1 > pair.Item2);
    }
}

P.S。我不太明白你的问题所以我刚刚开始实施你的问题。

答案 1 :(得分:1)

这样可行(使用@ gaeron的想法公开IEnumerable值以便于访问)

public static bool operator >(Foo foo1, Foo foo2)
{
    if (foo1 == null || foo2 == null)
        return false;

    var zipSeq = foo1.Values.Zip(foo2.Values, (a, b) => a - b);
    bool isGreater = zipSeq.All(x => x >= 0) && zipSeq.Any(x => x > 0);

    return isGreater;
}

基本思路是,foo1大于foo2foo1.Values中每个元素与foo2.Values中相应元素的减法必须为&gt; = 0并且必须至少有一个条目>&gt; 0