Search code examples
c#enumerable

How to instruct irregular course in Enumerable in C#?


Panagiotis Kanavos introduced the following clever solution to produce LetterNumberNumber pattern in this SOF question: For loop when the values of the loop variable is a string of the pattern LetterNumberNumber?

var maxLetters=3; // Take 26 for all letters    
var maxNumbers=3; // Take 99 for all the required numbers   

var values=from char c in Enumerable.Range('A',maxLetters).Select(c=>(char)c)    
       from int i in Enumerable.Range(1,maxNumbers)    
       select String.Format("{0}{1:d2}",(char)c,i);    

foreach(var value in values)    
{    
    Console.WriteLine(value);    
}    

A01 A02 A03 B01 B02 B03 C01 C02 C03 D01 D02 D03

Is there way to instruct irregular course in Enumerable stuff? "Enumerable.Range(1, maxNumbers)" leads 01, 02, ...,99 (for maxNumbers 99).

Restriction Examples:
1. Restrict (01,02,...,99) only to (01,03,05,07,09,11,13)
2. Restrict (01,02,...,99) only to (02,04,06,08,10)
3. Restrict (01,02,...,99) only to (01,04,09,10)

What I did:
I worked "Enumarable", tried its methods like: Enumerable.Contains(1,3,5,7,9,13) gave big error, and I could not achieve to reach:
A01, A03, A05, ....,Z09, Z11, Z13.

If Enumarable is not suitable for this type of job, what do you offer to handle the problem?


Solution

  • This isn't a direct feature in C#, while it is in F#.

    F# example:

    [1..2..10]
    

    will produce a list of [1,3,5,7,9].

    You first example, "Restrict (01,02,...,99) only to (01,03,05,07,09,11,13)" can be achieved with

    Enumerable.Range(1,99).Where(x => x % 2 == 1).Take(7);
    

    The second example, "Restrict (01,02,...,99) only to (02,04,06,08,10)" can be achieved with

    Enumerable.Range(1,99).Where(x => x % 2 == 0).Take(5);
    

    And your third example, "Restrict (01,02,...,99) only to (01,04,09,10)" seems odd. I'm not sure what the pattern here is. If the last element isn't a typo, then starting at one and incrementing by 3, then 5, then 1 seems unclear, but here's a method that can accomplish it.

    public static IEnumerable<int> GetOddMutation(int start, int max, int count, List<int> increments) {
        int counter = 0;
        int reset = increments.Count - 1;
        int index = 0;
        int incremented = start;
        while(counter < count) {
            var previous = incremented;
            incremented += increments[index];
            index = index == reset ? 0 : index + 1;
            counter++;
            if(previous != incremented) //Avoid duplicates if 0 is part of the incrementation strategy. Alternatively, call .Distinct() on the method.
            yield return incremented;
        }
    }
    

    called with

    GetOddMutation(1,99,4, new List<int> {0,3,5,1})
    

    will result in [1,4,9,10]