Czy istnieje operator C # IN?


90

W SQL możesz użyć następującej składni:

SELECT *
FROM MY_TABLE
WHERE VALUE_1 IN (1, 2, 3)

Czy istnieje odpowiednik w C #? Wydaje się, że IDE rozpoznaje „in” jako słowo kluczowe, ale nie mogę znaleźć żadnych informacji na jego temat.

Czy można więc zrobić coś takiego:

int myValue = 1;
if (myValue in (1, 2, 3))
    // Do something

Zamiast

int myValue = 1;
if (myValue == 1 || myValue == 2 || myValue == 3)
    // Do something

Trochę to zredagowałem, aby wyjaśnić, co próbowałem porównać
Paul Michaels,

sprawdź kolejną odpowiedź dodaną przeze mnie
Pranay Rana


3
@chiccodoro, jeśli to pytanie zostało zadane wcześniej, oznacz je jako duplikat i opublikuj odpowiedź z linkiem do oryginalnego pytania, nie zostawiaj tylko negatywnego komentarza
Hannish

Odpowiedzi:


128

Jeśli chcesz napisać .In, możesz stworzyć rozszerzenie, które pozwoli ci to zrobić.

static class Extensions
{

    public static bool In<T>(this T item, params T[] items)
    {
        if (items == null)
            throw new ArgumentNullException("items");

        return items.Contains(item);
    }

}


class Program
{

    static void Main()
    {


        int myValue = 1;

        if (myValue.In(1, 2, 3))
            // Do Somthing...

        string ds = "Bob";

        if (ds.In("andy", "joel", "matt")) 
        // Do Someting...
    }
}

1
Pamiętaj tylko, aby dodać za pomocą System.Linq;
Tanner Ornelas

O wiele lepiej się czyta niż zawiera ... Łatwiej do zrozumienia
Konrad

85

List.Contains()czy myślę, że to czego szukasz. C # ma in keywordi nie maoperator służy do zupełnie innego celu niż to, do czego odwołujesz się w SQL.

Istnieją dwa sposoby używania insłowa kluczowego w C #. Załóżmy, że masz ciąg [] lub List w C #.

        string[] names; //assume there are some names;

        //find all names that start with "a"
        var results = from str in names
                      where str.StartsWith("a")
                      select str;

        //iterate through all names in results and print
        foreach (string name in results)
        {
            Console.WriteLine(name);
        }

Odnosząc się do twojej zmiany, umieściłbym twój kod w ten sposób, aby zrobić to, czego potrzebujesz.

        int myValue = 1;
        List<int> checkValues = new List<int> { 1, 2, 3 };

        if (checkValues.Contains(myValue))
            // Do something 

4
Ludzie widzą SQL i natychmiast przechodzą do LINQ, ale ta prosta funkcja jest prawdopodobnie dokładnie tym, czego chce
Bart van Heukelom

30

Możesz to zrobić:

var x = 99; // searched value

if (new[] {1,2,3,99}.Contains(x))
{
   // do something
}

2
Wolałem tę odpowiedź od tych, które uzyskały wyższą liczbę głosów, ponieważ celem wykonania IN zamiast wielokrotnych sprawdzeń równości jest zmniejszenie złożoności kodu, a to jest ładne, krótkie i proste!
MrVimes

1
Dziękuję @MrVimes!
JwJosefy

7

Zwykle używasz Containsmetody kolekcji.

myCollection.Where(p => Enumerable.Range(1,3).Contains(p));

Mam nadzieję, że to pomoże.


6

W języku C # nie ma operatora „in”, słowo kluczowe „in” jest używane tylko z „foreach (... in ...)” lub „from ... in ...”.

Odpowiednik LINQ zapytania SQL wyglądałby następująco:

List<int> list = new List<int> { 1, 2, 3 };
var query = from row in my_table
            where list.Contains(row.value1)
            select row;

4

Duplikat: LINQ to SQL w i nie w

select * from table where fieldname in ('val1', 'val2') 

lub

select * from table where fieldname not in (1, 2) 

Odpowiednik zapytań IN i NOT IN w LINQ to SQL wyglądałby mniej więcej tak:

List<string> validValues = new List<string>() { "val1", "val2"}; 
var qry = from item in dataContext.TableName 
          where validValues.Contains(item.FieldName) 
          select item; 

i to:

List<int> validValues = new List<int>() { 1, 2}; 
var qry = from item in dataContext.TableName 
          where !validValues.Contains(item.FieldName) 
          select item; 

Tak - przepraszam, zredagowałem moje pytanie, ponieważ to, o co pytam, nie dotyczy linq
Paul Michaels

4

Zgadzam się, że najlepszym sposobem implementacji operatora In jest metoda rozszerzenia. Zrobiłem to trochę inaczej:

public static bool In(this string str, string CommaDelimintedStringSet)
{
    string[] Values = CommaDelimintedStringSet.Split(new char[] { ',' });
    foreach (string V in Values)
    {
       if (str == V)
         return true;
    }
    return false;
}

Różnica polega na tym, że nie musisz umieszczać cudzysłowów wokół każdej wartości, tylko cały zestaw wartości rozdzielanych przecinkami, co jest łatwiejsze do wpisania:

bool result = MyString.In("Val1,Val2,Val3");

Byłoby lepiej, gdybyśmy wykorzystali tablice parametrów z tą funkcją. Polub public static bool In(this string str, params string[] stringSet)i nazwij to jakbool result = myString.In("Val1", "Val2", "Val3")
Manuel Hoffmann

2

Możesz napisać rozszerzenie. Kiedyś pisałem o tworzeniu kodu w stylu

if(someObject.stringPropertyX.Equals("abc") || someObject.stringPropertyX.Equals("def") || ....){
    //do something
    ...
}else{
   //do something other...
   ....
}

bardziej czytelny z rozszerzeniem, które można było pisać

if(someObject.stringPropertyX.In("abc", "def",...,"xyz"){
   //do something
   ...
}else{
  //do something other...
  ....
}

Oto kod :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Some.Namespace.Extenders
{
    public static class StringExtender
    {
        /// <summary>
        /// Evaluates whether the String is contained in AT LEAST one of the passed values (i.e. similar to the "in" SQL clause)
        /// </summary>
        /// <param name="thisString"></param>
        /// <param name="values">list of strings used for comparison</param>
        /// <returns><c>true</c> if the string is contained in AT LEAST one of the passed values</returns>
        public static bool In(this String thisString, params string[] values)
        {
            foreach (string val in values)
            {
                if (thisString.Equals(val, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }

            return false; //no occurence found
        }
    }
}

To jest specyficzne dla moich potrzeb w tamtym czasie, ale możesz go dostosować i zmodyfikować, aby pasował do większej liczby różnych typów.


2

Dla cyfr od 0 do 9:

"123".Contains(myValue)

W przypadku innych rzeczy:

"|1|2|3|".Contains("|" + myValue + "|")

2

W przypadku zaktualizowanego pytania możesz również użyć instrukcji przełączającej.

switch (myvalue)
{
   case 1:
   case 2:
   case 3: 
      // your code goes here
  break;
}

1
Oto, co ostatecznie zrobiłem. Przypuszczam, że konsensus jest taki, że w C # tak naprawdę nie ma na to żadnego ułatwienia.
Paul Michaels,

5
Naprawdę bym tego nie zaakceptował, ponieważ NIE jest to odpowiedź na pytanie operatora „in”. Zamiast tego zobacz odpowiedź z największą
liczbą głosów

6
W ogóle nie polecałbym tego podejścia! Nie jest skalowalny i może uprzykrzyć życie innym programistom!
decyklon

3
@decyclone: ​​Tak, wszystko zależy od łatwości konserwacji. tak jakby następny programista, który cię zastąpił, był seryjnym mordercą i wiedział, gdzie mieszkasz.
to. __curious_geek

Nie zgadzam się, nie było rzeczywistej odpowiedzi na pytanie (lub odpowiedź brzmiała „nie, tego nie ma w C #”) - więc to wydawało mi się najbliższą alternatywą. Należy również pamiętać, że pytanie dotyczyło funkcjonalności języka, a nie stylu.
Paul Michaels,

1

Nie ma operatora, który szuka wartości w kolekcji, zamiast tego jest to metoda kolekcji o nazwie Contains .

Najbardziej skalowalnym rozwiązaniem jest użycie HashSetjako kolekcji. Sprawdzanie wartości w a HashSetjest zbliżone do operacji O (1), w porównaniu do wykonywania tego w operacji a, Listgdzie jest to operacja O (n). Oznacza to, że możesz spakować wiele wartości w a HashSeti jest to nadal szybkie, podczas gdy szukasz wartości w aList jest tym wolniejsze, im więcej masz wartości.

Przykład:

var set = new HashSet<int>();
set.Add(1);
set.Add(2);
set.Add(3);

var result = items.Select(i => set.Contains(i.value));

1

Wspólne, LINQ o wiele bardziej wydajne:

var list = new List<string> { "Tomato", "Orange", "Mango"};
var query = from i in my_table
            from v in list
            where i.Name.StartsWith(v)
            select i;

0

Słowo inkluczowe w C # jest przeznaczone dla foreachinstrukcji i dla wyrażeń zapytań LINQ. Nie ma funkcji odpowiadającej inoperatorowi SQL w C # per se, ale LINQ oferuje podobną funkcjonalność z Contains().

var list = {1, 2, 3}
var filtered = (
    from item in items
    where list.Contains(item)
    select item).ToArray().

0

Robię coś takiego:

var shippingAddress = checkoutContext.Addresses.Where(a => (new HashSet<AddressType> { AddressType.SHIPPING_ONLY, AddressType.BILLING_AND_SHIPPING }).Contains(a.AddressType) && a.Id == long.Parse(orderDto.ShippingAddressId)).FirstOrDefault();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.