LINQ-如何比较组中的前两个项目然后比较下一个?

时间:2019-02-27 09:11:13

标签: c# linq

我有两个集合A和B。集合A的所有内容之和应为0(它们具有将其推送到集合A的唯一标识符),而集合B的总和不必为0。例如:< / p>

item1 = 200; 
item2 = -200; 
item3 = 200

这些不等于0,但是具有相同的唯一ID,现在位于集合A中。我想将它们分组并比较前两个项目,如果它们合计为0,我将移至该组中的下一个项目如果这些项目的总和不为0,我想将其移至集合B。

这就是我现在拥有的:

var grp= colA.AsEnumerable()
        .Where(a => a.Field<string>("unique_id") != null)
        .GroupBy(b=> b["unique_id"])
        .Where(c=> c.Count() > 1).ToList();
foreach(var d in grp)
{
  var sum = d.AsEnumerable().Sum(e => e.Field<decimal>("amount"));
}
if(sum != 0){//compare rows in group}

这成功地将不等于0的项目进行了分组,但是我在如何比较item1和item2然后比较item3时陷入了困境,以便可以将item3移至集合B,然后集合A的总和为0。

2 个答案:

答案 0 :(得分:1)

这样会帮助您吗?

grp.ForEach(g => 
{
    int stepNumber = 0;
    int step = 2;
    var target = g.Skip(stepNumber * step).Take(step);

    if (target.Sum(x => x.Field<decimal>("amount")) != 0)
    {
        foreach (var item in target.Select(x => x))
        {
            colA.Rows.Remove(item);
            colB.Rows.Add(item);
        }
    }

    stepNumber ++;
});

答案 1 :(得分:0)

如果您使用“跳过/获取”来枚举序列,则将一遍又一遍地从序列的开头开始。这可以做得更聪明!

按以下顺序有点不清楚您想要什么:

200, -200, 10, 11, -11, 12, -12, 13, -13

200和-200留在集合A中。但是,您是否只删除10个,并让A中的对[11,-11],[12,-12],[13,-13]删除? [10,11],[-11,12],[-12,13],-13?

让我们假设您想要后者。您需要将输入序列分成两个对。为此,让我们制作一个可重用的功能。

输入:一系列项目和splitSize 输出:一系列ICollection,其中每个ICollection都具有splitsize(最后一个除外)

因此输入:0 1 2 3 4 5 6 7 8 9和SplitSize 3 输出:[0 1 2] [3 4 5] [6 7 8] [9]

我将其创建为扩展方法,因此可以在LINQ串联中使用它。参见extension methods demystified

public static IEnumerable<IList<TSource>> Split<TSource>(this IEnumerable<TSource> source,
    int splitSize)
{
    // todo: check for non-null source and positive splitSize

    var enumerator = source.GetEnumerator();
    while (enumerator.MoveNext())
    {
       // still elements to process. Create and fill the next splitList
       List<TSource> splitList = new List<TSource>(splitSize);
       splitList.Add(enumerator.Current()
       while (splitList.Count < splitSize && enumerator.MoveNext())
       {
           // still elements to add:
           splitList.Add(enumerator.Current);
       }
       // if here: either no more elements, or splitList full.
       yield return splitList;
    }
}

借助此功能,我们可以将输入分为[0 1] [2 3] [4 5]对,并检查它们应属于零和还是非零和的集合:

void CreateZeroSumCollections<TSource>(IEnumerable<TSource> source,
     Func<TSource, int> keySelector,
     out IList<TSource> zeroCollection,
     out IList<TSource> nonzeroCollection)
{
    var zeroCollection = new List<TSource>();
    var nonzeroCollection = new List<TSource>();

    var splitSource = source.Split(2);
    foreach (var splitElement in splitSource)
    {
        // the splitElement has a length of 2 or less
        // Check if the sum is zero
        if (splitElement.Count == 2 
            && keySelector(splitElement[0]) == -keySelector(splitElement[1])
        {   // 2 elements, and sum is zero
            zeroCollection.AddRange(splitElement);
        }
        else
        {   // either only 1 element or non zero sum
            nonzeroCollection.AddRange(splitElement);
        }
    }
}

为此,您的序列仅需枚举一次。