IEnumerable,其中全部满足 X 并且至少有一个满足 y

发布于 2024-10-16 20:50:49 字数 2382 浏览 1 评论 0原文

我有 2 个 IEnumerable。例如 {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;}}
}

amp

  • 如果全部满足 >= (如 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 的信息和答案受到欢迎,就像使用不涉及反射的相同比较功能来解决可变属性长度的整个问题一样。

不过,我目前正在 .net 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、更少的编码和更多的重用?

I have 2 IEnumerable<decimal>. for example {0,0.1,0.5,1} and {a,b,c,d}
assume equal lengths

Sample Domain Object Code:

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

I want to define Foo1>Foo2

  • if all meet >= (as in Foo1.A>=Foo2.A && ' .. 'Foo1.C>=Foo2.C ..)
  • At least one > (as in Foo1.B>Foo2.B)

Sample iterative code:

//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;
}

information and answers involving zip are welcomed from a learning perspective, as are attacking the entire problem of variable property lengths using the same comparison functionality that don't involve reflection.

However, I'm currently working within the confines of .net 2.0 with LinqBridge.

I'm considering something like the following to cover all classes that need the same functionality

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

    }

The Question(s):

Is there an existing Linq keyword/operator combination that will do all this more gracefully?
Is there a more elegant/simpler way to do this type of comparison that is better DRY, less coding, and more reuse?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北渚 2024-10-23 20:50:49

这是可行的(使用 @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 中相应的元素相减必须 >=0 并且必须至少有一个条目 >=0 0。

This would work (using @gaeron's idea to expose IEnumerable of values to ease access)

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

The basic idea is that for foo1 to be greater than foo2, the subtraction of each element in foo1.Values with the corresponding one in foo2.Values must be >=0 AND there must at least be one entry that is > 0.

亚希 2024-10-23 20:50:49

尚未测试,但只需稍加修改就应该可以工作。

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

PS我不太明白你的问题,所以我只是实现了你一开始所问的内容。

Haven't tested but with little modifications it should work.

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. I didn't quite understand your question so I just implemented what you asked in the beginning.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文