views:

207

answers:

5

I want to test whether a certain string is contained in a short list of strings. Currently the code is like this:

if (new List<string> { "A", "B", "C" }.Contains (str)) {

However, this seems bloated. For instance, iirc, in Java I could simply write {"A", "B", "C"}.Contains(str) which would be much preferable to the above.

I'm sure there is a better way in C#. Could you point it out?

+6  A: 

I guess you could shorten it down to:

if ((new []{ "A", "B", "C" }).Contains (str)) {

Don't know how much of an actual difference it would make though.

Update: if you know that you will be testing for exactly one letter, I see no reason to make a list or array of it:

if ("ABC".Contains(str)) {

That code is both shorter and faster. But then again I guess that the single-letter strings were merely samples...

Fredrik Mörk
That's already a big improvement. I guess it is a bit faster as well.
mafutrct
@mafutrct: I did a performance test and it seems as if my solution is actually slower. So right now it's a choice between shorter or faster code ;o)
Fredrik Mörk
Luckily right now I actually need to test for single characters only. How could I possibly miss "ABC".Contains?!
mafutrct
+2  A: 

What about this approach:

"A;B;C".Split(';').Contains(str);
Christian
It's a bit shorter, but also less easy to read and the performance is probably worse.
mafutrct
s/probably/certainly/ - don't stick that inside a loop...
ijw
Of course the performance is worse. If it matters in the op's case is another question :)
Christian
+2  A: 

If your short list of strings are constant, you should use a static readonly string array.

The benefit is it's easy to write and it does not instantiate new List every time you need to perform the check.

private static readonly string[] Names = new string[] { "A", "B", "C" };

...

if (Names.Contains(str)) {

However, this solution is not scalable as the search is done in a linear fashion. Alternatively, you can define your constant array in a sorted manner and use BinarySearch over the array.

// this has to be sorted
private static readonly string[] Names = new string[] { "A", "B", "C" };

...

if (Array.BinarySearch(Names, str) >= 0) {
Fnop
From a performance POV, I like your solution. However, my main concern was code length.
mafutrct
+2  A: 

To completely change it up:

switch(str){
    case "A":
    case "B":
    case "C":
       contains = true;
       break;

    default:
       contains = false;
       break;
}
Noon Silk
Too much code :)
mafutrct
Just offering an alternative :)
Noon Silk
+4  A: 

You could write an extension method:

public static bool In<T>(this T obj, params T[] candidates)
{
    return obj.In((IEnumerable<T>)candidates);
}

public static bool In<T>(this T obj, IEnumerable<T> candidates)
{
    if(obj == null) throw new ArgumentNullException("obj");
    return (candidates ?? Enumerable.Empty<T>()).Contains(obj);
}

Which you could then use to do:

if(str.In("A", "B", "C")) { ... }
Lee
An interesting approach. Right now I like Fredrik's second solution better, but I will keep your idea in mind. +1
mafutrct
Decided to accept this answer anyway, as it is more universal.
mafutrct