Imran Rizvi
Imran Rizvi

Reputation: 7438

Is there any compare operator in C# like SQL's IN statement

I have to check one variable if it contains a value from a list of strings, for e.g.:

status == "Open" || status =="Active" || status =="Reopen" || status = "Inactive" etc..

In SQL it is very easy to write this kind of statement, e.g.:

select * from ticket where status in ("Open","Active","Reopen","Inactive")

I wonder whether we don't have such easy statement in C#?

Do anybody know any easy way like SQL to write this kind of statements without using generic types of if else, foreach loop, or LINQ, etc.

I know LINQ is there, but still it is not as simple as the in feature of SQL.

Upvotes: 5

Views: 3907

Answers (4)

nimblebit
nimblebit

Reputation: 559

Its possible to create an extension method that can handle this as mentioned earlier...

Add the necessary imports

using System;
using System.Linq; // required if using .Contains() or .Any()
using System.Collections.Generic;

Create an Extension class. The following gives three options for the extension method.

public static class Extensions
{
    
    public static bool InV1(this string input, string[] collection)
    {       
        if (collection == null || collection.Length == 0)
        {
            throw new ArgumentException("Parameters empty");
        }

        for (int i = 0; i < collection.Length; i++) 
        {
            if (input.Equals(collection[i]))
            {
                return true;
            }
        }
        
        return false;
    }
    
    public static bool InV2(this string input, string[] collection)
    {   
        if (collection == null || collection.Length == 0)
        {
            throw new ArgumentException("Parameters empty");
        }

        if (collection.Contains(input))
        {
            return true;
        }
        
        return false;
    }
    
    // Credit: https://stackoverflow.com/a/3165188/1165173
    public static bool InV3<T>(this T input, params T[] items)
    {   
        if (input == null)
        {
            throw new ArgumentException("Input is empty");
        }
        
        if (items == null || items.Length == 0)
        {
            throw new ArgumentException("Parameters empty");
        }
        
        return items.Any(i => i.Equals(input)); // Any() function exists immediately on first item
    }
}

Invoke the extension method within your business logic.

public class Program
{
    public static void Main()
    {
        var input = "test1";
        
        var collection = new [] { "test1", "test2", "test3", "test4", "test5" };
        
        // using contains
        var result1 = input.InV1(collection);
        
        Console.WriteLine(result1);
        
        // using iteration
        var result2 = input.InV2(collection);
        
        Console.WriteLine(result2);
        
        // using linq
        var result3 = input.InV3("test1", "test2", "test3", "test4", "test5");

        Console.WriteLine(result3);
        
        // recursively
        var salesIds = new List<int>() { 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239 };
        
        foreach (var id in salesIds)
        {
            if (id.InV3(1230, 1238, 1239))
            {
                Console.WriteLine("exists: " + id);
            }
        }
    }
}

UPDATE: .NET 9 preview makes this even easier, you can use the following...

using System;
using System.Buffers;
                    
public class Program
{
    // Credit: Nick Chapsas - 25/03/2024
    // https://www.youtube.com/watch?v=q0VENoIXWso
    public static void Main()
    {
        SearchValues<string> searchValues = SearchValues.Create(["Test A", "Test B"], StringComparison.OrdinalIgnoreCase);
        Console.WriteLine(searchValues.Contains("Test B"));
        // or another way
        Console.WriteLine(MemoryExtensions.ContainsAny("Test A", searchValues));
    }
}

Upvotes: -1

Imran Rizvi
Imran Rizvi

Reputation: 7438

This works for me.

(new List<string>{ "Open", "Active", "Reopen", "InActive" }).Contains("status");

I also like the c# 3.0 feature of creating extension to String class

public static class StringExtensions
{
    public static bool In(this string @this, params string[] strings)
    {
        return strings.Contains(@this); 
    }
}

and later we can use it in Simplest way

status.Contains("Open", "Active", "Reopen", "InActive");

This is great if you have to write many statements like this I prefer to write this extension for if I am writing old style for atleast 5-10 statement statement in 2 or more files.

Upvotes: 1

YoryeNathan
YoryeNathan

Reputation: 14522

tickets.Where(t => new[] {"Open",
                          "Active",
                          "Reopen",
                          "InActive"}.Any(x => x == t.status))

You can also use the Contain method instead of the Any method, but use the Any method if there's any comparement logic you would like to implement, instead of the default equality comparer.

OR

Implement extensions to support IN method:

public static class Extensions
{
    public static bool In<TItem>(this TItem source, Func<TItem, TItem, bool> comparer, IEnumerable<TItem> items)
    {
        return items.Any(item => comparer(source, item));
    }

    public static bool In<TItem, T>(this TItem source, Func<TItem, T> selector, IEnumerable<TItem> items)
    {
        return items.Select(selector).Contains(selector(source));
    }

    public static bool In<T>(this T source, IEnumerable<T> items)
    {
        return items.Contains(source);
    }

    public static bool In<TItem>(this TItem source, Func<TItem, TItem, bool> comparer, params TItem[] items)
    {
        return source.In(comparer, (IEnumerable<TItem>)items);
    }

    public static bool In<TItem, T>(this TItem source, Func<TItem, T> selector, params TItem[] items)
    {
        return source.In(selector, (IEnumerable<TItem>)items);
    }

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

And use like this:

bool b;

b = 7.In(3, 5, 6, 7, 8); // true
b = "hi".In("", "10", "hi", "Hello"); // true
b = "hi".In("", "10", "Hi", "Hello"); // false
b = "hi".In((s1, s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase), "", "10", "Hi"); // true

var tuples = new List<Tuple<int, string>>();

for (var i = 0; i < 10; i++)
{
    tuples.Add(Tuple.Create(i, ""));
}

var tuple = Tuple.Create(3, "");

b = tuple.In(tup => tup.Item1, tuples); // true

Upvotes: 12

dmytro.s
dmytro.s

Reputation: 720

(new [] { "Open", "Active", "Reopen", "InActive" }).Contains(status)

Upvotes: 9

Related Questions