How to perform LINQ query over Enum?

66,934

Solution 1

Well if you're going to hard code the items that should be in the list anyway, why not just do this:

public static List<Activity.StatusEnum> StatusList()
{
    return new List<Activity.StatusEnum>
    { 
        Activity.StatusEnum.Open, 
        Activity.StatusEnum.Rejected, 
        Activity.StatusEnum.Accepted, 
        Activity.StatusEnum.Started 
    };
}

You could also dispose of the List<T> and just return the array itself. As long as you know these are the items you want, then there's no need for Linq.

Solution 2

return Enum.GetValues(typeof(Activity.StatusEnum)).Cast<Activity.StatusEnum>().Where((n, x) => x < 4);

If you want to be able to change the list of items, just add them into a List<Activity.StatusEnum> and use Contains:

var listValid = new List<Activity.StatusEnum>() { Activity.StatusEnum.Open, Activity.StatusEnum.Rejected, Activity.StatusEnum.Accepted, Activity.StatusEnum.Started };
return Enum.GetValues(typeof(Activity.StatusEnum)).Cast<Activity.StatusEnum>().Where(n => listValid.Contains(n));

Solution 3

Steps:

  • Get the enum values and cast the results to the type of the enum
  • Sort the enum values by their integer values (otherwise they sort naturally by unsigned magnitude)
  • Take the first 4

Code:

return Enum.GetValues(typeof(Activity.StatusEnum))
.Cast<Activity.StatusEnum>()
.OrderBy(se =>(int)se)
.Take(4);

Output:

Open Rejected Accepted Started

Solution 4

First, if possible, I'd make your enum values powers of 2, so they could be OR'd together.

public enum StatusEnum
{
    Open = 1,
    Rejected = 2,
    Accepted = 4,
    Started = 8,
    Completed = 16,
    Cancelled = 32,
    Assigned = 64
}

Then you could do something like this:

public static List<Activity.StatusEnum> StatusList()
{
    var statusesToShow = Activity.StatusEnum.Open | Activity.StatusEnum.Rejected | Activity.StatusEnum.Accepted | Activity.StatusEnum.Started;

    return Enum
        .GetValues(typeof(Activity.StatusEnum))
        .Cast<Activity.StatusEnum>()
        .Where(x => (x & statusesToShow) == x)
        .ToList();
}

EDIT: In light of the fact that you can't change the enum values, I'd just recommend you use something like:

public static List<Activity.StatusEnum> StatusList()
{
    return new List<Activity.StatusEnum> {
        Activity.StatusEnum.Open, 
        Activity.StatusEnum.Rejected, 
        Activity.StatusEnum.Accepted, 
        Activity.StatusEnum.Started
    };
}

Solution 5

". . . only show the first 4 statuses and ignore the rest."

To get the first n elements of an IEnumerable<T>, use the Take method:

return Enum.GetValues(typeof(Activity.StatusEnum))
    .Cast<Activity.StatusEnum>()
    .Take(4)
    .ToList();
Share:
66,934
Learner
Author by

Learner

Updated on March 22, 2020

Comments

  • Learner
    Learner about 4 years

    Below is my Enumerator List:

    public enum StatusEnum
    {
        Open = 1,
        Rejected = 2,
        Accepted = 3,
        Started = 4,
        Completed = 5,
        Cancelled = 6,
        Assigned = 7
    }
    

    I need to bind this to a Combobox, but, only show a few specific statuses and ignore the rest.

    This is what I have so far:

    public static List<Activity.StatusEnum> StatusList()
    {
            IEnumerable<Activity.StatusEnum> query = Enum.GetValues(typeof(Activity.StatusEnum)).Cast<Activity.StatusEnum>()
                            .Where(x => x == Activity.StatusEnum.Open
                                || x == Activity.StatusEnum.Rejected
                                || x == Activity.StatusEnum.Accepted
                                || x == Activity.StatusEnum.Started);
            return query.ToList();
    }
    

    However, I feel that the code is little messy and is not a correct approach to bind filtered Enum list to a Combobox. Can anyone suggest a more robust way of doing this?

    Update

    I might need to change the Order of selection. So I need a generic solution which doesn't only get the first X number of statuses.

  • Yinda Yin
    Yinda Yin almost 11 years
    I was thinking along these lines, but the use of a magic number bothers me. Maybe compare to (int)StatusEnum.Started?
  • It'sNotALie.
    It'sNotALie. almost 11 years
    @RobertHarvey He said 4, not to compare against Started. It bothers me too, but this does exactly what asked. Unlike the most upvoted answer, too.
  • Learner
    Learner almost 11 years
    It's a good solution for this scenario, but I might need to change the order in future. Like just show Open, Completed and Assigned.
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen almost 11 years
    Upvoted, but he should either change the return type into the array type Activity.StatusEnum[], like you suggest, or use collection initializer syntax on the List<> (just remove the five charaters new[] and the parenthesis ()). It is crazy to allocate an array that is immediately discarded again (only the List<> is kept)!
  • Learner
    Learner almost 11 years
    Sorry for the confusion but, I need a solution without Take(4) as the order might change for other situations.
  • It'sNotALie.
    It'sNotALie. almost 11 years
    @RobertHarvey I'd prefer to make a List and use Contains tbh
  • Learner
    Learner almost 11 years
    Very sorry for the confusion about quoted text. Please see the update. But this will help me. +1
  • Learner
    Learner almost 11 years
    Thanks for the suggestion but I am using objects which I don't have control over. +1 for solution.
  • p.s.w.g
    p.s.w.g almost 11 years
    @JeppeStigNielsen Thanks, I'd forgotten about collection initializers.
  • Chris Doggett
    Chris Doggett almost 11 years
    @Learner: In that case, you don't need to use Enum.GetValues at all, and can just initialize a List<T> with the known enums, which would be much easier. I'd also recommend using an IEnumerable<T> instead of List<T>, unless the binding specifically requires a List<T>.
  • Learner
    Learner almost 11 years
    May I know the reason for recommending IEnumerable<T>?
  • Chris Doggett
    Chris Doggett almost 11 years
    In general, it's considered a best practice to prefer using interfaces over specific implementations. If your code that calls this expects an IEnumerable<T>, it doesn't matter if the function itself uses List<T>, HashSet<T>, T[] (array), or any other implementation. It would only care that there's a number of items it can iterate over. It would also prevent code that called it from calling .Add() on the List<T>. Basically, you just want to give users what they NEED access to, and nothing more. It's probably overkill for this, but it's just generally a good practice.
  • Learner
    Learner almost 11 years
    BTW, I will wait for Android version of Milestone ;)
  • Piotr Kula
    Piotr Kula over 10 years
    What the heck is <= I have not seen that before!? :) Is that meant to be lest or equal or some other linq function I have never seen before?
  • Bronek
    Bronek over 7 years
    @ppumkin it's "less than or equal" operator :)
  • Piotr Kula
    Piotr Kula over 7 years
    So embarrassing:) noob at Linq 3 years ago. :D
  • John Bustos
    John Bustos over 7 years
    Right, @ppumkin??? - I look at some of my old questions and LOVE to see how far I've come! - Got to absolutely love this community for how much they've helped!!!!
  • Piotr Kula
    Piotr Kula over 7 years
    Completely agreed. So many problems solved, some pages are boookmarked because I keep on forgetting, like complex Grouping with Linq :) But for sure, since Spolsky opened Stack Overflow, the quality of code increased by 66%, globally :)