按顺序搜索缺失的数字

时间:2018-01-10 16:22:36

标签: c# linq

假设我有以下数组(我的序列都按升序排序,并包含正整数)

var tabSequence = new[] { 1, 2, 3, 7, 8, 9, 12, 15, 16, 17, 22, 23, 32 };

我使用LINQ和循环来编写一个代码来搜索缺少的数字:

List<Int32> lstSearch = new List<int>();
var lstGroup = tabSequence
    .Select((val, ind) => new { val, group = val - ind })
    .GroupBy(v => v.group, v => v.val)
    .Select(group => new{ GroupNumber = group.Key, Min = group.Min(), Max = group.Max() }).ToList();

for (int number = 0; number < lstGroup.Count; number++)
{
    if (number < lstGroup.Count-1)
    {
        for (int missingNumber = lstGroup[number].Max+1; missingNumber < lstGroup[number+1].Min; missingNumber++) 
            lstSearch.Add(missingNumber);
    }               
}       
var tabSequence2 = lstSearch.ToArray();
// Same result as var tabSequence2 = new[] {4, 5, 6, 10, 11, 13, 14, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31 };

此代码有效,但我想知道是否有更好的方法只使用linq做同样的事情。

2 个答案:

答案 0 :(得分:6)

也许我只是不理解这个问题。你的代码看起来很复杂,你可以把它变得更简单:

int[] tabSequence = new[] { 1, 2, 3, 7, 8, 9, 12, 15, 16, 17, 22, 23, 32 };

var results = Enumerable.Range(1, tabSequence.Max()).Except(tabSequence);

//results is: 4, 5, 6, 10, 11, 13, 14, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31

我做了一个小提琴here

答案 1 :(得分:0)

您可以使用IEnumerable.Aggregate。我选择的重载使用累加器种子(空List<IEnumerable<int>>)并继续遍历数组中的每个项目。

我第一次设置lastNR之前定义的聚合到我们迭代的最新数。我们将实际nr的nexts迭代与此lastNr进行比较。

  • 如果我们按顺序进行,我们只需增加lastNr
  • 如果没有,我们会在lastNr之间通过Enumerable.Range(a,count)生成缺失的数字 和实际的nr并将它们添加到我们的累加器列表中。然后我们将lastNr设置为nr以继续。
public static List<IEnumerable<int>> GetMissingSeq(int[] seq)
{
    var lastNr = int.MinValue;
    var missing = seq.Aggregate(
        new List<IEnumerable<int>>(),
        (acc, nr) =>
        {
            if (lastNr == int.MinValue || lastNr == nr - 1)
            {
                lastNr = nr; // first ever or in sequence
                return acc;  // noting to do
            }

            // not in sequence, add the missing into our ac'umulator list
            acc.Add(Enumerable.Range(lastNr + 1, nr - lastNr - 1));
            lastNr = nr; //thats the new lastNR to compare against in the next iteration
            return acc;
        }
    );
    return missing;
}

测试者:

public static void Main(string[] args)
{
    var tabSequence = new[] { 1, 2, 3, 7, 8, 9, 12, 15, 16, 17, 22, 23, 32 };

    var lastNr = int.MinValue;
    var missing = tabSequence.Aggregate(
        new List<IEnumerable<int>>(),
        (acc, nr) =>
        {
            if (lastNr == int.MinValue || lastNr == nr - 1)
            {
                lastNr = nr; // first ever or in sequence
                return acc;  // noting to do
            }

            acc.Add(Enumerable.Range(lastNr + 1, nr - lastNr - 1));
            return acc;
        }
    );

    Console.WriteLine(string.Join(", ", tabSequence));

    foreach (var inner in GetMissingSeq(tabSequence))
        Console.WriteLine(string.Join(", ", inner));

    Console.ReadLine();
}

输出:

1, 2, 3, 7, 8, 9, 12, 15, 16, 17, 22, 23, 32  // original followed by missing sequences
4, 5, 6
10, 11
13, 14
18, 19, 20, 21
24, 25, 26, 27, 28, 29, 30, 31

如果您对子序列不感兴趣,可以使用GetMissingSeq(tabSequence).SelectMany(i => i)将它们展平为一个IEnumerable。