C# 如何使用LINQ来比较“sequential”的值;“邻居”;在列表中<>;?

C# 如何使用LINQ来比较“sequential”的值;“邻居”;在列表中<>;?,c#,.net,linq,lambda,sequence,C#,.net,Linq,Lambda,Sequence,请看下面的代码: ColorResult contains Index, Color Name, and Probability Colors.Add(new ColorResult(1, "Unknown", 5f)); Colors.Add(new ColorResult(2, "Blue", 80f)); Colors.Add(new ColorResult(3, "Blue", 80f)); Colors.

请看下面的代码:

        ColorResult contains Index, Color Name, and Probability

        Colors.Add(new ColorResult(1, "Unknown", 5f));
        Colors.Add(new ColorResult(2, "Blue", 80f));
        Colors.Add(new ColorResult(3, "Blue", 80f));
        Colors.Add(new ColorResult(4, "Green", 40f));
        Colors.Add(new ColorResult(5, "Blue", 80f));
        Colors.Add(new ColorResult(6, "Blue", 80f));
        Colors.Add(new ColorResult(7, "Red", 20f));
        Colors.Add(new ColorResult(8, "Blue", 80f));
        Colors.Add(new ColorResult(9, "Green", 5f));
使用LINQ,您将如何完成以下任务:

1) 按顺序操作,当概率高于60的前两项具有相同值时,替换列表开头概率低于60的所有项(“未知”变为“蓝色”,因为#2和#3为蓝色,概率为60+)

2) 替换概率低于60且周围有四个相邻项具有相同值的任何项(“绿色”变为“蓝色”,因为#2、#3、#5和#6为蓝色且概率为60+)

3) 按顺序操作,替换列表末尾前面有两个值相同的项(与第一部分相同,但相反)的任何项。在样本数据中#9不会发生任何变化,因为#7需要是“蓝色”并且需要60+概率

这对于循环来说非常容易,但是我完全不知道如何比较LINQ中的顺序“邻居”

这是我第一部分的原始解决方案:

        bool partOneCompleted = false;
        for (int i = 0; i < Colors.Count; i++)
        {
            if (Colors[i].ResultConfidence > 60)
            {
                // This item does not need to be changed
                partOneCompleted = true;
            }
            if (!partOneCompleted)
            {
                int twoItemsAway = i + 2;
                if (twoItemsAway < Colors.Count)
                {
                    if (Colors[twoItemsAway].Name == Colors[twoItemsAway - 1].Name && Colors[twoItemsAway].ResultConfidence > 60 && Colors[twoItemsAway - 1].ResultConfidence > 60)
                    {
                        // The next item, and the one after that both have the same value and 60+ confidence
                        for (int loopBack = i; loopBack >= 0; loopBack--)
                        {
                            Colors[loopBack].Name = Colors[twoItemsAway].Name;
                        }

                        partOneCompleted = true;
                    }
                }
            }
        }
[Test]
public void Should_convert_leading_low_probability_colors()
{
    var colors = new List<ColorResult>
        {
            new ColorResult(1, "Unknown", 5f),
            new ColorResult(2, "Blue", 80f),
            new ColorResult(3, "Blue", 80f),
            new ColorResult(4, "Green", 40f),
            new ColorResult(5, "Blue", 80f),
            new ColorResult(6, "Blue", 80f),
            new ColorResult(7, "Red", 20f),
            new ColorResult(8, "Blue", 80f),
            new ColorResult(9, "Green", 5f)
        };

    ConvertLeadingLowProbabilityColors(colors);

    foreach (var colorResult in colors)
    {
        Console.WriteLine(colorResult.Index + " " + colorResult.Color);
    }

    colors[0].Color.ShouldBeEqualTo("Blue");
    colors[1].Color.ShouldBeEqualTo("Blue");
    colors[2].Color.ShouldBeEqualTo("Blue");
    colors[3].Color.ShouldBeEqualTo("Green");
    colors[4].Color.ShouldBeEqualTo("Blue");
    colors[5].Color.ShouldBeEqualTo("Blue");
    colors[6].Color.ShouldBeEqualTo("Red");
    colors[7].Color.ShouldBeEqualTo("Blue");
    colors[8].Color.ShouldBeEqualTo("Green");
}
bool partOneCompleted=false;
for(int i=0;i60)
{
//此项不需要更改
partOneCompleted=true;
}
如果(!partOneCompleted)
{
int twoItemsAway=i+2;
if(twoItemsAway60&&Colors[twoItemsAway-1].ResultConfidence>60)
{
//下一项和之后的一项都具有相同的值和60+置信度
对于(int loopBack=i;loopBack>=0;loopBack--)
{
颜色[loopBack]。名称=颜色[twoItemsAway]。名称;
}
partOneCompleted=true;
}
}
}
}

任何LINQ专家都可以分享最有效的实现吗?

这里是第一个例子,让您开始。键使用的是
Enumerable.Range
,因此您有了索引。如前所述,使用循环将更具可读性

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace ConsoleApplication1
{
    public class ColorResult
    {
        public int Index;
        public string Name;
        public float Prob;

        public ColorResult(int Index, string Name, float Prob)
        {
            this.Index = Index;
            this.Name = Name;
            this.Prob = Prob;
        }

        public override string ToString()
        {
            return Index.ToString() + ", " + Name + ", " + Prob.ToString();
        }
    }

    class Program
    {
        public static void Main()
        {
            List<ColorResult> Colors = new List<ColorResult>();

            Colors.Add(new ColorResult(1, "Unknown", 5f));
            Colors.Add(new ColorResult(2, "Blue", 80f));
            Colors.Add(new ColorResult(3, "Blue", 80f));
            Colors.Add(new ColorResult(4, "Green", 40f));
            Colors.Add(new ColorResult(5, "Blue", 80f));
            Colors.Add(new ColorResult(6, "Blue", 80f)); 
            Colors.Add(new ColorResult(7, "Red", 20f)); 
            Colors.Add(new ColorResult(8, "Blue", 80f));   
            Colors.Add(new ColorResult(9, "Green", 5f));


            var test1 = from i in Enumerable.Range(0, Colors.Count)
                        select (i < Colors.Count - 2 &&
                               (Colors[i].Prob < 60f) &&
                               (Colors[i + 1].Name == Colors[i + 2].Name) &&
                               (Colors[i+1].Prob > 60f) &&
                               (Colors[i+2].Prob > 60f)) ?
                        new ColorResult(1, Colors[i + 1].Name, Colors[i].Prob) :
                        Colors[i];


        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统图;
使用System.Linq;
命名空间控制台应用程序1
{
公共类着色结果
{
公共整数指数;
公共字符串名称;
公众浮存问题;
公共ColorResult(int索引、字符串名称、float Prob)
{
这个。索引=索引;
this.Name=Name;
这个.Prob=Prob;
}
公共重写字符串ToString()
{
返回Index.ToString()+”,“+Name+”,“+Prob.ToString();
}
}
班级计划
{
公共静态void Main()
{
列表颜色=新列表();
添加(新的颜色结果(1,“未知”,5f));
添加(新的颜色结果(2,“蓝色”,80f));
添加(新的颜色结果(3,“蓝色”,80f));
添加(新的颜色结果(4,“绿色”,40f));
添加(新的颜色结果(5,“蓝色”,80f));
添加(新的颜色结果(6,“蓝色”,80f));
颜色。添加(新的颜色结果(7,“红色”,20f));
添加(新的颜色结果(8,“蓝色”,80f));
添加(新的颜色结果(9,“绿色”,5f));
var test1=可枚举范围(0,Colors.Count)中的从i开始
选择(i60f)&&
(颜色[i+2]。概率>60f))?
新颜色结果(1,颜色[i+1]。名称,颜色[i]。问题):
颜色[i];
}
}
}

这里有一个基于收益率的解决方案,我想这不是严格意义上的LINQ,但它类似于LINQ。实施迅速;我相信有更好的方法可以做到这一点。为窃取乔治的测试框架向他道歉(和+1)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace ConsoleApplication1
{
  public class ColorResult
  {
    public int Index;
    public string Name;
    public float Prob;

    public ColorResult(int Index, string Name, float Prob)
    {
      this.Index = Index;
      this.Name = Name;
      this.Prob = Prob;
    }

    public override string ToString()
    {
      return Index.ToString() + ", " + Name + ", " + Prob.ToString();
    }
  }

  class Program
  {
    // Iterate through the list remembering the last two elements
    // to implement rule 1
    public static IEnumerable<ColorResult> Rule1(IEnumerable<ColorResult> input)
    {
      ColorResult last2 = null;
      ColorResult last1 = null;
      foreach (var color in input)
      {
        if ((color.Prob < 60f)
            && (last1 != null) && (last1.Prob >= 60f)
            && (last2 != null) && (last2.Prob >= 60f)
            && (last2.Name == last1.Name))
        {
          color.Name = last2.Name;
        }
        yield return color;
        last2 = last1;
        last1 = color;
      }
    }

    // Iterate through the list with two element look-ahead
    // to implement rule 3
    public static IEnumerable<ColorResult> Rule3(IEnumerable<ColorResult> input)
    {
      ColorResult color = null;
      ColorResult ahead1 = null;
      foreach (var ahead2 in input)
      {
        if ((color != null) && (color.Prob < 60f)
            && (ahead1 != null) && (ahead1.Prob >= 60f)
            && (ahead2 != null) && (ahead2.Prob >= 60f)
            && (ahead1.Name == ahead2.Name))
        {
          color.Name = ahead1.Name;
        }
        yield return color;
        color = ahead1;
        ahead1 = ahead2;
      }
      // Using a null check here as a cheat way to test we've
      // actually had two inputs.
      // NB Will not preserve trailing nulls in the list;
      // you'll need to count inputs if you need that.
      if (color != null) yield return color;
      if (ahead1 != null) yield return ahead1;
    }

    public static void Main()
    {
      List<ColorResult> Colors = new List<ColorResult>();

      Colors.Add(new ColorResult(1, "Unknown", 5f));
      Colors.Add(new ColorResult(2, "Blue", 80f));
      Colors.Add(new ColorResult(3, "Blue", 80f));
      Colors.Add(new ColorResult(4, "Green", 40f));
      Colors.Add(new ColorResult(5, "Blue", 80f));
      Colors.Add(new ColorResult(6, "Blue", 80f));
      Colors.Add(new ColorResult(7, "Red", 20f));
      Colors.Add(new ColorResult(8, "Blue", 80f));
      Colors.Add(new ColorResult(9, "Green", 5f));

      var processed = Rule3(Rule1(Colors));
      foreach (var color in processed)
      {
        Console.WriteLine(color);
      }
    }
  }
}
使用系统;
使用System.Collections.Generic;
使用系统图;
使用System.Linq;
命名空间控制台应用程序1
{
公共类着色结果
{
公共整数指数;
公共字符串名称;
公众浮存问题;
公共ColorResult(int索引、字符串名称、float Prob)
{
这个。索引=索引;
this.Name=Name;
这个.Prob=Prob;
}
公共重写字符串ToString()
{
返回Index.ToString()+”,“+Name+”,“+Prob.ToString();
}
}
班级计划
{
//反复浏览列表,记住最后两个元素
//实施规则1
公共静态IEnumerable规则1(IEnumerable输入)
{
ColorResult last2=null;
ColorResult last1=null;
foreach(输入中的var颜色)
{
如果((color.Prob<60f)
&&(last1!=null)&(last1.Prob>=60f)
&&(last2!=null)和&(last2.Prob>=60f)
&&(last2.Name==last1.Name))
{
color.Name=last2.Name;
}
退色率;
last2=last1;
last1=颜色;
}
}
//使用两个元素的“向前看”遍历列表
//执行规则3
公共静态IEnumerable规则3(IEnumerable输入)
{
ColorResult color=null;
ColorResult ahead1=null;
foreach(输入中的var ahead2)
{
如果((color!=null)&&(color.Prob<60f)
&&(ahead1!=null)和&(ahead1.Prob>=60f)
&&(ahead2!=null)和&(ahead2.Prob>=60f)
&&(ahead1.Name==ahead2.Name))
{
color.Name=ahead1.Name;
        bool startComplete = false;
        for (int i = 0; i < Colors.Count; i++)
        {
            if (Colors[i].ResultConfidence > 60)
            {
                // This item does not need to be changed
                startComplete = true;
            }
            if (!startComplete)
            {
                int twoItemsAway = i + 2;
                if (twoItemsAway < Colors.Count)
                {
                    if (Colors[twoItemsAway].Name == Colors[twoItemsAway - 1].Name && Colors[twoItemsAway].ResultConfidence > 60 && Colors[twoItemsAway - 1].ResultConfidence > 60)
                    {
                        // The next item, and the one after that both have the same value and 60+ confidence
                        for (int loopBack = i; loopBack >= 0; loopBack--)
                        {
                            Colors[loopBack].Name = Colors[twoItemsAway].Name;
                        }

                        startComplete = true;
                    }
                }
            }
        }

        bool endComplete = false;
        for (int i = Colors.Count - 1; i >= 0; i--)
        {
            if (Colors[i].ResultConfidence > 60)
            {
                // This item does not need to be changed
                endComplete = true;
            }
            if (!endComplete)
            {
                int twoItemsAway = i - 2;
                if (twoItemsAway >= 0)
                {
                    if (Colors[twoItemsAway].Name == Colors[twoItemsAway + 1].Name && Colors[twoItemsAway].ResultConfidence > 60 && Colors[twoItemsAway + 1].ResultConfidence > 60)
                    {
                        // The next item, and the one after that both have the same value and 60+ confidence
                        for (int loopForward = twoItemsAway; loopForward < Colors.Count; loopForward++)
                        {
                            Colors[loopForward].Name = Colors[twoItemsAway].Name;
                        }

                        endComplete = true;
                    }
                }
            }
        }

        // Fill in the middle values.

        for (int i = 2; i < Colors.Count - 2; i++)
        {
            if (Colors[i].ResultConfidence < 60)
            {
                int twoLeft = i - 2;
                int oneLeft = i - 1;
                int oneRight = i + 1;
                int twoRight = i + 2;

                if (Colors[twoLeft].Name == Colors[oneLeft].Name && Colors[oneLeft].Name == Colors[oneRight].Name && Colors[oneRight].Name == Colors[twoRight].Name
                    &&
                    Colors[twoLeft].ResultConfidence > 60 && Colors[oneLeft].ResultConfidence > 60 && Colors[oneRight].ResultConfidence > 60 && Colors[twoRight].ResultConfidence > 60)
                {
                    Colors[i].Name = Colors[oneRight].Name;
                }

            }
        }
[Test]
public void Should_convert_leading_low_probability_colors()
{
    var colors = new List<ColorResult>
        {
            new ColorResult(1, "Unknown", 5f),
            new ColorResult(2, "Blue", 80f),
            new ColorResult(3, "Blue", 80f),
            new ColorResult(4, "Green", 40f),
            new ColorResult(5, "Blue", 80f),
            new ColorResult(6, "Blue", 80f),
            new ColorResult(7, "Red", 20f),
            new ColorResult(8, "Blue", 80f),
            new ColorResult(9, "Green", 5f)
        };

    ConvertLeadingLowProbabilityColors(colors);

    foreach (var colorResult in colors)
    {
        Console.WriteLine(colorResult.Index + " " + colorResult.Color);
    }

    colors[0].Color.ShouldBeEqualTo("Blue");
    colors[1].Color.ShouldBeEqualTo("Blue");
    colors[2].Color.ShouldBeEqualTo("Blue");
    colors[3].Color.ShouldBeEqualTo("Green");
    colors[4].Color.ShouldBeEqualTo("Blue");
    colors[5].Color.ShouldBeEqualTo("Blue");
    colors[6].Color.ShouldBeEqualTo("Red");
    colors[7].Color.ShouldBeEqualTo("Blue");
    colors[8].Color.ShouldBeEqualTo("Green");
}
private void ConvertLeadingLowProbabilityColors(IList<ColorResult> colors)
{
    var leadingBelow60 = Enumerable
        .Range(0, colors.Count)
        .TakeWhile(index => colors[index].Probability < 60)
        .ToList();
    if (leadingBelow60.Count > 0 && leadingBelow60.Count < colors.Count - 2)
    {
        int lastIndex = leadingBelow60.Last();
        var firstNext = colors[lastIndex + 1];
        var secondNext = colors[lastIndex + 2];
        if (firstNext.Probability > 60 &&
            secondNext.Probability > 60 &&
            firstNext.Color == secondNext.Color)
        {
            leadingBelow60.ForEach(index => colors[index].Color = firstNext.Color);
        }
    }
}
[Test]
public void Should_convert_trailing_low_probability_colors()
{
    var colors = new List<ColorResult>
        {
            new ColorResult(1, "Unknown", 5f),
            new ColorResult(2, "Blue", 80f),
            new ColorResult(3, "Blue", 80f),
            new ColorResult(4, "Green", 40f),
            new ColorResult(5, "Blue", 80f),
            new ColorResult(6, "Blue", 80f),
            new ColorResult(7, "Red", 20f),
            new ColorResult(8, "Blue", 40f),
            new ColorResult(9, "Green", 5f)
        };

    ConvertTrailingLowProbabilityColors(colors);

    foreach (var colorResult in colors)
    {
        Console.WriteLine(colorResult.Index + " " + colorResult.Color);
    }

    colors[0].Color.ShouldBeEqualTo("Unknown");
    colors[1].Color.ShouldBeEqualTo("Blue");
    colors[2].Color.ShouldBeEqualTo("Blue");
    colors[3].Color.ShouldBeEqualTo("Green");
    colors[4].Color.ShouldBeEqualTo("Blue");
    colors[5].Color.ShouldBeEqualTo("Blue");
    colors[6].Color.ShouldBeEqualTo("Blue");
    colors[7].Color.ShouldBeEqualTo("Blue");
    colors[8].Color.ShouldBeEqualTo("Blue");
}
private void ConvertTrailingLowProbabilityColors(IList<ColorResult> colors)
{
    var trailingBelow60 = Enumerable
        .Range(0, colors.Count)
        .Select(i => colors.Count - 1 - i)
        .TakeWhile(index => colors[index].Probability < 60)
        .ToList();
    if (trailingBelow60.Count > 0 && trailingBelow60.Count < colors.Count - 2)
    {
        int lastIndex = trailingBelow60.Last();
        var firstPrevious = colors[lastIndex - 1];
        var secondPrevious = colors[lastIndex - 2];
        if (firstPrevious.Probability > 60 &&
            secondPrevious.Probability > 60 &&
            firstPrevious.Color == secondPrevious.Color)
        {
            trailingBelow60.ForEach(index => colors[index].Color = firstPrevious.Color);
        }
    }
}
[Test]
public void Should_convert_surrounded_low_probability_colors()
{
    var colors = new List<ColorResult>
        {
            new ColorResult(1, "Unknown", 5f),
            new ColorResult(2, "Blue", 80f),
            new ColorResult(3, "Blue", 80f),
            new ColorResult(4, "Green", 40f),
            new ColorResult(5, "Blue", 80f),
            new ColorResult(6, "Blue", 80f),
            new ColorResult(7, "Red", 20f),
            new ColorResult(8, "Blue", 80f),
            new ColorResult(9, "Green", 5f)
        };

    ConvertSurroundedLowProbabilityColors(colors);

    foreach (var colorResult in colors)
    {
        Console.WriteLine(colorResult.Index + " " + colorResult.Color);
    }

    colors[0].Color.ShouldBeEqualTo("Unknown");
    colors[1].Color.ShouldBeEqualTo("Blue");
    colors[2].Color.ShouldBeEqualTo("Blue");
    colors[3].Color.ShouldBeEqualTo("Blue");
    colors[4].Color.ShouldBeEqualTo("Blue");
    colors[5].Color.ShouldBeEqualTo("Blue");
    colors[6].Color.ShouldBeEqualTo("Red");
    colors[7].Color.ShouldBeEqualTo("Blue");
    colors[8].Color.ShouldBeEqualTo("Green");
}
private void ConvertSurroundedLowProbabilityColors(IList<ColorResult> colors)
{
    var surrounding4Modification = new Surrounding4ModificationStrategy();
    foreach (int index in Enumerable
        .Range(0, colors.Count)
        .Where(index => surrounding4Modification.IsMatch(colors, index)))
    {
        surrounding4Modification.Update(colors, index);
    }
}
public class Surrounding4ModificationStrategy
{
    public bool IsMatch(IList<ColorResult> input, int index)
    {
        if (index < 2)
        {
            return false;
        }
        if (index >= input.Count - 2)
        {
            return false;
        }
        if (input[index].Probability >= 60)
        {
            return false;
        }

        var secondPrevious = input[index - 2];
        if (secondPrevious.Probability < 60)
        {
            return false;
        }
        var firstPrevious = input[index - 1];
        if (firstPrevious.Probability < 60)
        {
            return false;
        }

        var firstNext = input[index + 1];
        if (firstNext.Probability < 60)
        {
            return false;
        }
        var secondNext = input[index + 2];
        if (secondNext.Probability < 60)
        {
            return false;
        }

        if (new[] { secondPrevious.Color, firstPrevious.Color, firstNext.Color, secondNext.Color }.Distinct().Count() > 1)
        {
            return false;
        }
        return true;
    }

    public void Update(IList<ColorResult> input, int index)
    {
        input[index].Color = input[index + 1].Color;
    }
}
[Test]
public void Should_convert_all_low_probability_colors()
{
    var colors = new List<ColorResult>
        {
            new ColorResult(1, "Unknown", 5f),
            new ColorResult(2, "Blue", 80f),
            new ColorResult(3, "Blue", 80f),
            new ColorResult(4, "Green", 40f),
            new ColorResult(5, "Blue", 80f),
            new ColorResult(6, "Blue", 80f),
            new ColorResult(7, "Red", 20f),
            new ColorResult(8, "Blue", 80f),
            new ColorResult(9, "Green", 5f)
        };

    ConvertLowProbabilityColors(colors);

    foreach (var colorResult in colors)
    {
        Console.WriteLine(colorResult.Index + " " + colorResult.Color);
    }

    colors[0].Color.ShouldBeEqualTo("Blue");
    colors[1].Color.ShouldBeEqualTo("Blue");
    colors[2].Color.ShouldBeEqualTo("Blue");
    colors[3].Color.ShouldBeEqualTo("Blue");
    colors[4].Color.ShouldBeEqualTo("Blue");
    colors[5].Color.ShouldBeEqualTo("Blue");
    colors[6].Color.ShouldBeEqualTo("Red");
    colors[7].Color.ShouldBeEqualTo("Blue");
    colors[8].Color.ShouldBeEqualTo("Green");
}
public void ConvertLowProbabilityColors(IList<ColorResult> colors)
{
    ConvertLeadingLowProbabilityColors(colors);
    ConvertSurroundedLowProbabilityColors(colors);
    ConvertTrailingLowProbabilityColors(colors);
}
  var colours = new List<string>(new[]{"red", "green", "blue"});
  var added = colours
              .Skip(1)
              .Zip(colours,
              (second, first) => first + second);
  foreach (var colour in added)
  {
    Console.WriteLine(colour);
  }