C#
iteration
integer range
range manipulation
programming tips

Does C have a nice way of iterating through every integer in a range, minus 1 of them?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, iterating across a numeric range while skipping one specific value is common and does not require anything exotic. The right approach depends on whether you want maximum clarity, minimum allocation, or a more declarative LINQ style.

The Simple and Fast Approach

For most cases, a plain for loop with continue is the best answer. It is explicit, efficient, and easy to debug.

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        int start = 1;
8        int end = 10;
9        int excluded = 5;
10
11        for (int i = start; i <= end; i++)
12        {
13            if (i == excluded)
14            {
15                continue;
16            }
17
18            Console.WriteLine(i);
19        }
20    }
21}

This prints every integer from 1 through 10 except 5. If you only need iteration, this is usually the cleanest implementation.

A LINQ Version for Declarative Code

If the surrounding code already uses LINQ and you want a sequence you can pass around, Enumerable.Range combined with Where is a good fit.

csharp
1using System;
2using System.Linq;
3
4class Program
5{
6    static void Main()
7    {
8        int start = 1;
9        int end = 10;
10        int excluded = 5;
11
12        var numbers = Enumerable.Range(start, end - start + 1)
13            .Where(i => i != excluded);
14
15        foreach (var number in numbers)
16        {
17            Console.WriteLine(number);
18        }
19    }
20}

The tradeoff is that this is slightly less direct than a loop, and you need to remember that Enumerable.Range takes a start and a count, not a start and an end.

Excluding More Than One Value

If the requirement grows from "skip one number" to "skip a set of numbers," the loop still works, but a HashSet<int> makes the intent cleaner and keeps lookups fast.

csharp
1using System;
2using System.Collections.Generic;
3
4class Program
5{
6    static void Main()
7    {
8        var excluded = new HashSet<int> { 3, 5, 8 };
9
10        for (int i = 1; i <= 10; i++)
11        {
12            if (excluded.Contains(i))
13            {
14                continue;
15            }
16
17            Console.WriteLine(i);
18        }
19    }
20}

That scales better than chaining many if checks once the skip logic becomes more dynamic.

When You Actually Need a Reusable Iterator

If the pattern appears in several places, wrap it in an iterator method. This preserves readability without paying the cost of building a list eagerly.

csharp
1using System;
2using System.Collections.Generic;
3
4class Program
5{
6    static IEnumerable<int> RangeExcept(int start, int endInclusive, int excluded)
7    {
8        for (int i = start; i <= endInclusive; i++)
9        {
10            if (i != excluded)
11            {
12                yield return i;
13            }
14        }
15    }
16
17    static void Main()
18    {
19        foreach (var value in RangeExcept(1, 10, 5))
20        {
21            Console.WriteLine(value);
22        }
23    }
24}

This becomes useful when the iteration pattern is part of your domain logic, not just a one-off loop.

Choosing Between the Options

Use a for loop when:

  • performance matters
  • the logic is local
  • you want the fewest moving parts

Use LINQ when:

  • you need to compose a sequence with other filters
  • you are already working in a query-heavy code path
  • readability benefits from a declarative style

Use a custom iterator when:

  • the pattern is reused
  • the exclusion rule belongs in a named abstraction

There is no deeper language trick here. The nice way is the one that matches the job.

Edge Cases Worth Checking

You should still think through the boundaries:

  • what happens if start is greater than end
  • whether the range is inclusive or exclusive
  • whether the excluded number falls outside the range

For example, if excluded is 99 and the range is 1 to 10, nothing special should happen. That is usually fine, but it is worth making deliberate.

Common Pitfalls

The most common mistake with LINQ is forgetting that Enumerable.Range(start, count) expects a count, not the final value. Using Enumerable.Range(1, 10) is correct for 1 through 10, but Enumerable.Range(5, 10) gives 5 through 14, not 5 through 10.

Another mistake is reaching for a clever abstraction too early. A plain loop is often better than a helper method or query chain if the logic appears once.

Developers also sometimes build a full list just to iterate it once. If you only need streaming iteration, prefer yield return or a direct loop.

Finally, be explicit about whether the upper bound is included. Many off-by-one bugs come from mixing inclusive and exclusive range rules.

Summary

  • In C#, the simplest solution is usually a for loop with continue.
  • 'Enumerable.Range(...).Where(...) is a good declarative alternative when you need a composable sequence.'
  • A custom iterator with yield return is useful when the pattern is reused.
  • Be careful with Enumerable.Range, because its second argument is a count.
  • Decide on inclusive versus exclusive bounds up front to avoid off-by-one errors.

Course illustration
Course illustration

All Rights Reserved.