使用LINQ的反馈循环过滤查询

时间:2016-02-24 20:40:40

标签: c# linq

我有以下场景(基于此处无法显示的实际场景)。两个输入

  1. 一个数字x
  2. IEnumerable<int>
  3. 给出的一系列正整数

    现在我想找到系列中三个连续整数的所有组,这些组可以除x而没有余数,一组不能与另一组重叠。

    例如:我的系列是1,2,3,4,5,6和用户输入x=24

    然后我的LINQ将给出1,2,3,但不会给2,3,4,因为这两个组将在系列中重叠。

    现在我可以运行LINQ查询,该查询基本上会运行一个&#34;窗口&#34;系列中的3个,并给我几个组,并运行Where子句来查找将成功划分x的所有3个数字的组。但每次我找到匹配项时,我都需要某种负面反馈来告诉我的过滤器省略后续的重叠到匹配组的组。

    在上面的例子中,要更好地理解它。我可以生成几个像

    这样的组
    1, 2, 3
    2, 3, 4
    3, 4, 5,
    and so on
    

    然后我可以说

    myWindowsOf3Numbers
          .Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
    

    所以我最终得到了像这样的代码

    var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
    var x = 24;
    
    var windows = series.Select((number, index) => index + 2 < series.Count()? new { Number1 = series[index], Number2 = series[index+1], Number3 = series[index+2]  } :  null )
        .Where(groups => groups != null);
    
    var matching = windows.Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0);
    

    以上将给我1,2,3和2,3,4两者,但我只希望两者中的第一个重叠。

    有没有LINQ技巧要做,或者我必须使用foreach(如下面的代码)?

    private class Match
    {
        public int N1 { get; set; }
        public int N2 { get; set; }
        public int N3 { get; set; }
    }
    
    var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
    var x = 24;
    
    var windows = series.Select((number, index) => index + 2 < series.Count() ? new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2] } : null)
        .Where(groups => groups != null);
    
    var matches = new List<Match>();
    
    for (var i = 0; i < (series.Count() - 2); i ++)
    {
        if (x % series[i] == 0 && x % series[i + 1] == 0 && x % series[i + 2] == 0)
        {
            matches.Add(new Match() { N1 = series[i], N2 = series[i + 1], N3 = series[i + 2] });
            i += 3;
        }
    }
    

2 个答案:

答案 0 :(得分:1)

为了迎接挑战,这里有一个可能的&#34;纯粹的&#34; LINQ解决方案,但坦率地说我永远不会使用这样的东西:

int x = 60;
var series = new [] { 1, 2, 3, 4, 5, 6 }.AsEnumerable();
var matches = series
    // Create the sliding window
    .Select((e, i) => new { index = i, group = series.Skip(i).Take(3).ToArray() })
    // Remove the non matching
    .Where(e => e.group.Length == 3 && e.group.All(v => (x % v) == 0))
    // Remove the overlapping 
    .Aggregate(new { next = 0, result = Enumerable.Empty<int[]>() }, (prev, next) => 
        next.index >= prev.next ?
        new { next = next.index + 3, result = prev.result.Concat(new[] { next.group }) } :
        prev).result;

答案 1 :(得分:0)

嗯,你说LINQ ......:

        var series = new[] { 1, 2, 3, 4, 5, 6, 7 };
        var x = 24;

        var matchingWindows = series
            .Select((number, index) => index + 2 < series.Length ? 
            new { Number1 = series[index], Number2 = series[index + 1], Number3 = series[index + 2], Index = index } : 
            null)
            .Where(groups => groups != null)
            .Where(w => x % w.Number1 == 0 && x % w.Number2 == 0 && x % w.Number3 == 0)
            .ToList();

        int lastTakenIndex = -1;

        var nonOverlapping = matchingWindows.Where(w =>
        {
            if (lastTakenIndex >= 0)
            {
                if (w.Index <= lastTakenIndex + 2) return false;

                lastTakenIndex = w.Index;
                return true;
            }

            lastTakenIndex = w.Index;

            return true;
        }).ToList();

它使用lastTakenIndex(=最后一次匹配条件的3组的起始索引),在Where过滤期间被修改为副作用。

相关问题