user215675
user215675

Reputation: 5181

C# LINQ Autogenerated number or index

When deriving combination,what is the possible way to generate auto generate numbers.

public enum Color
{
    Red,Green,Blue
}

public enum Vehicle
{
    Car,Bike
}

(i.e) {Red,Car},{Red,Bike},{Green,Car},{Green,Bike}......

(Jon Skeet helped me to solve it).

var query = from Color c in Enum.GetValues(typeof(Color))
            from Vehicle v in Enum.GetValues(typeof(Vehicle))
            select new { Color = c, Vehicle = v };

Now I want the combination like this

{1,Red,Car},{2,Red,Bike},{3,Green,Car},{4,Green,Bike},{5,Blue,Car},{6,Blue,Bike}

What is the way to generate auto numbers?

Upvotes: 2

Views: 4007

Answers (3)

Marcel Valdez Orozco
Marcel Valdez Orozco

Reputation: 3015

Solution #1: I believe this is the most efficient LINQ-Like solution. It uses the permutation count to enumerate efficiently; in reality, it can work for any Enum that doesn't change the default values (0,1,2,.. n)

int colorCount = Enum.GetValues(typeof(Color)).Length;
int vehicleCount = Enum.GetValues(typeof(Vehicle)).Length;
var permutations = Enumerable
                   .Range(0, colorCount * vehicleCount)
                    .Select (index => 
                               new {
                                     Index = index + 1,
                                     Color = (Color)(index / colorCount),
                                     Vehicle = (Vehicle)(index % vehicleCount)
                                   });

Solution #2: This one is in reality the most efficient solution, since it won't actually enumerate anything, giving you an O(1) solution, but it has an ugly hack there that does (T)(object)(int). Use at your risk.

class Permutations<T1, T2> : IEnumerable<Tuple<int, T1, T2>>
    where T1 : struct
    where T2 : struct
{
    int countT1 = 0;
    int countT2 = 0;

    public Permutations()
    {
        countT1 = Enum.GetValues(typeof(T1)).Length;
        countT2 = Enum.GetValues(typeof(T2)).Length;        
    }

    public int Length
    {
        get {
            return countT1 * countT2;
        }
    }

    public Tuple<int, T1, T2> this[int index]
    {
        get {
            Contract.Requires(index >= 1, "Index is out of lower bounds: Options are 1 - N.");
            Contract.Requires(index <= Length, "Index is out of upper bound.");                 
            return new Tuple<int, T1, T2>(
                       index,
            /*Hack ->*/(T1)(object)((index - 1) / countT1),
            /*Hack ->*/(T2)(object)((index - 1) % countT2));
        }
    }

    public IEnumerator<Tuple<int, T1, T2>> GetEnumerator()
    {
        return Enumerable.Range(1, this.Length).Select (i => this[i]).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

void Main()
{       
    var permutations = new Permutations<Color, Vehicle>();
    // Can be accesed individually:
    var permutation = permutations[1];
    // Can be accesed using Enumerations
    permutations.Dump(); // LINQPad Dump
}

Upvotes: 0

Ahmad Mageed
Ahmad Mageed

Reputation: 96557

Another option is to use the overloaded Select method that includes an item's index. Building on your original query, you could use this:

var indexedQuery = query.Select((item, i) => new { Index = i + 1, Item = item });
foreach (var o in indexedQuery)
{
   Console.WriteLine("{0},{1},{2}", o.Index, o.Item.Color, o.Item.Vehicle);
}

Upvotes: 9

eglasius
eglasius

Reputation: 36035

Try:

int optionNumber = 0;
var query = from Color c in Enum.GetValues(typeof(Color))
            from Vehicle v in Enum.GetValues(typeof(Vehicle))
            select new { Number = optionNumber++, Color = c, Vehicle = v };

Upvotes: 6

Related Questions