Как использовать LINQ Contains (string []) вместо Contains (string)

У меня есть один большой вопрос.

Я получил запрос linq, чтобы выразить это просто так:

from xx in table
where xx.uid.ToString().Contains(string[])
select xx

Значения массива string[] будут числами типа (1,45,20,10 и т. д.).

Значение по умолчанию для .Contains - .Contains(string).

Вместо этого мне нужно это сделать: .Contains(string[]) ...

РЕДАКТИРОВАТЬ : Один пользователь предложил написать класс расширения для string[]. Я хотел бы узнать, как это сделать, но кто-нибудь хочет указать мне в правильном направлении?

РЕДАКТИРОВАТЬ : uid также будет числом. Вот почему он конвертируется в строку.

Кому-нибудь помочь?

Вам необходимо уточнить, как будет выглядеть uid и что будет считаться совпадением.

James Curran 12.10.2008 07:01

Было бы неплохо привести пример. Мне кажется, что вопрос задает UID, например: CA1FAB689C33, и массив, например: {"42", "2259", "CA"}

Thomas Bratt 12.10.2008 13:38

Противоположное имеет больше смысла: строка []. Содержит (xx.uid)

majkinetor 04.03.2010 17:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
102
3
418 298
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Как насчет:

from xx in table
where stringarray.Contains(xx.uid.ToString())
select xx

NotSupportedException: операторы сравнения не поддерживаются для типа System.String []. Спасибо, но попробуйте еще раз?

SpoiledTechie.com 12.10.2008 05:31

+1, если они действительно этого хотят. Не очень понятно из вопроса.

Lucas 14.10.2008 22:24

Это пример одного из способов написания метода расширения (примечание: я бы не стал использовать его для очень больших массивов; более подходящей была бы другая структура данных ...):

namespace StringExtensionMethods
{
    public static class StringExtension
    {
        public static bool Contains(this string[] stringarray, string pat)
        {
            bool result = false;

            foreach (string s in stringarray)
            {
                if (s == pat)
                {
                    result = true;
                    break;
                }
            }

            return result;
        }
    }
}

это было бы идентично общедоступному статическому типу bool Contains (this string [] stringarray, string pat) {return Array.IndexOf (stringarray, pat)! = -1; }

James Curran 12.10.2008 06:52

string [] реализует IEnumerable <string>, поэтому у него уже есть метод расширения Contains (string). Почему мы перерабатываем это?

Lucas 14.10.2008 02:50

Я считаю, что вы тоже могли бы сделать что-то подобное.

from xx in table
where (from yy in string[] 
       select yy).Contains(xx.uid.ToString())
select xx

То же, что и «where stringArray.Contains (xx.uid.ToString ())», нет необходимости оборачивать его в запросе

Lucas 14.10.2008 02:51
Ответ принят как подходящий

Споулсон почти прав, но сначала вам нужно создать List<string> из string[]. На самом деле List<int> было бы лучше, если бы uid также был int. List<T> поддерживает Contains(). Выполнение uid.ToString().Contains(string[]) будет означать, что uid в виде строки содержит все значения массива в виде подстроки ??? Даже если бы вы написали метод расширения, смысл этого был бы неправильным.

[РЕДАКТИРОВАТЬ]

Если вы не изменили его и не написали для string[], как демонстрирует Митч Уит, вы просто сможете пропустить этап преобразования.

[КОНЕЦ]

Вот что вы хотите, если вы не используете метод расширения (если у вас еще нет коллекции потенциальных uid в виде целых чисел - тогда просто используйте вместо этого List<int>()). Здесь используется синтаксис цепочечного метода, который, на мой взгляд, чище, и выполняет преобразование в int, чтобы запрос можно было использовать с большим количеством поставщиков.

var uids = arrayofuids.Select(id => int.Parse(id)).ToList();

var selected = table.Where(t => uids.Contains(t.uid));

Спасибо. Это был правильный ответ ... Еще одна мысль? Допустим, arrayuids также является запросом linq. В любом случае, вы могли бы свести оба оператора к одному запросу из базы данных?

SpoiledTechie.com 13.10.2008 01:07

Согласно MSDN, string [] реализует IEnumerable <T>, который имеет метод Contains. Следовательно, нет необходимости преобразовывать массив в IList <T>. msdn.microsoft.com/en-us/library/19e6zeyy.aspx

spoulson 13.10.2008 05:11

Последний .ToString () вызывает у меня ошибки. В частности, LINQ to Entities не распознает метод System.String ToString (), и этот метод не может быть преобразован в выражение хранилища .... После его удаления лямбда сработала для меня.

Sam Stange 21.09.2011 19:00

Мне это нравится, это так просто, что я никогда этого не помню.

Olaj 28.09.2011 09:17

@SamStange - одна проблема с LINQ заключается в том, что существует так много вариантов, а абстракция «дырявая», вам иногда нужно знать, какой вариант вы используете, чтобы правильно построить запрос. Как написано, это будет работать для LINQ to objects (и может быть LINQ to SQL). Для EF вы должны сделать это наоборот и вместо этого создать коллекцию в памяти как List<int> и пропустить вызов ToString.

tvanfosson 28.09.2011 16:34

HashSet будет еще быстрее

paparazzo 26.05.2015 21:02

@Blam, если только это не запрос, который конвертируется в SQL, что, я думаю, было контекстом в то время.

tvanfosson 26.05.2015 21:16

Попробуйте следующее.

string input = "someString";
string[] toSearchFor = GetSearchStrings();
var containsAll = toSearchFor.All(x => input.Contains(x));

Я действительно хочу, чтобы люди оставляли комментарии, когда отмечали вас. Тем более, что ответ, который я дал, верен на 100%.

JaredPar 13.10.2008 08:47

Это был не я, но разве All () не возвращает просто логическое значение, указывающее, где все элементы соответствуют условию? И инициализация toSearchFor нулевым значением гарантирует исключение NullReferenceException.

Lucas 14.10.2008 02:46

Я отредактировал нулевую проблему так, чтобы она соответствовала тому, что собиралась ввести. Да на всех. Это эффективно гарантирует, что все строки в toSearchFor содержатся во входной строке.

JaredPar 15.10.2008 12:33

Я вообще не понимаю, как это отвечает на вопрос. Вопрос изменился на вас?

tvanfosson 04.02.2015 20:01

Если вы действительно хотите реплицировать Содержит, но для массива, вот метод расширения и пример кода для использования:

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

namespace ContainsAnyThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            string testValue = "123345789";

            //will print true
            Console.WriteLine(testValue.ContainsAny("123", "987", "554")); 

            //but so will this also print true
            Console.WriteLine(testValue.ContainsAny("1", "987", "554"));
            Console.ReadKey();

        }
    }

    public static class StringExtensions
    {
        public static bool ContainsAny(this string str, params string[] values)
        {
            if (!string.IsNullOrEmpty(str) || values.Length > 0)
            {
                foreach (string value in values)
                {
                    if (str.Contains(value))
                        return true;
                }
            }

            return false;
        }
    }
}

+1 @Jason, вы должны полностью отправить это ExtensionMethod.net Спасибо за отличный код, он решил мою проблему сегодня!

p.campbell 19.11.2009 21:33

Я думаю, вы имели в виду! String.IsNullOrEmpty (str) && values.Length> 0

Greg Bogumil 18.06.2010 23:03

Ты прав. Я его поменял, но функционального влияния не оказывает. Я использую такую ​​функцию на работе. Придется это проверить!

Jason Jackson 19.06.2010 03:58

@JasonJackson Я понимаю, что это старый (иш), но (как сказал Грег) разве вы не хотите, чтобы в этом условном выражении было «а также», а не «или еще»?

Tieson T. 06.09.2015 21:39

@TiesonT. И «or else», и «and also» в конечном итоге приведут к одному и тому же результату, возвращаемому функцией; если проверка !string.IsNullOrEmpty(str) пройдена, в результате чего условие values.Length > 0 будет проигнорировано, но длина значений была 0, тогда он перейдет к foreach, а затем немедленно прервется, потому что в массиве нет записей, перейдя непосредственно к return false.

Meowmaritus 01.10.2017 01:10

@ GreenCat77 Это правда, но зачем вообще зацикливаться, если в value нет элементов?

Tieson T. 01.10.2017 02:11

Наконец, пример, показывающий, как искать строки массива в другой строке.

nickornotto 30.01.2020 01:58

Грег Богумил прав, это должно быть && не || в операторе if. В противном случае первая проверка бессмысленна, если values не пуст.

Trisped 11.06.2020 01:18

Итак, правильно ли я предполагаю, что uid - это уникальный идентификатор (Guid)? Это просто пример возможного сценария или вы действительно пытаетесь найти guid, который соответствует массиву строк?

Если это правда, вы можете действительно переосмыслить весь этот подход, это кажется действительно плохой идеей. Вероятно, вам стоит попытаться сопоставить Guid с Guid

Guid id = new Guid(uid);
var query = from xx in table
            where xx.uid == id
            select xx;

Честно говоря, я не могу представить себе сценарий, при котором сопоставление строкового массива с использованием "contains" с содержимым Guid было бы хорошей идеей. Во-первых, Contains () не гарантирует порядок чисел в Guid, поэтому вы потенциально можете сопоставить несколько элементов. Не говоря уже о том, чтобы сравнивать направляющие таким образом, было бы намного медленнее, чем просто делать это напрямую.

Вы должны написать это наоборот, проверив, что ваш список идентификаторов привилегированных пользователей содержит идентификатор в этой строке таблицы:

string[] search = new string[] { "2", "3" };
var result = from x in xx where search.Contains(x.uid.ToString()) select x;

LINQ здесь ведет себя довольно ярко и преобразует его в хороший оператор SQL:

sp_executesql N'SELECT [t0].[uid]
FROM [dbo].[xx] AS [t0]
WHERE (CONVERT(NVarChar,[t0].[uid]))
IN (@p0, @p1)',N'@p0 nvarchar(1),
@p1 nvarchar(1)',@p0=N'2',@p1=N'3'

который в основном встраивает содержимое массива search в запрос sql и выполняет фильтрацию с помощью ключевого слова IN в SQL.

Это отлично работает, если у вас не более 2100 параметров.

jpierson 30.09.2013 08:13

Мне удалось найти решение, но не лучшее, поскольку для этого требуется использовать AsEnumerable (), который будет возвращать все результаты из БД, к счастью, у меня есть только 1k записей в таблице, поэтому на самом деле это не заметно, но вот .

var users = from u in (from u in ctx.Users
                       where u.Mod_Status != "D"
                       select u).AsEnumerable()
            where ar.All(n => u.FullName.IndexOf(n,
                        StringComparison.InvariantCultureIgnoreCase) >= 0)
            select u;

Мой исходный пост следует:

How do you do the reverse? I want to do something like the following in entity framework.

string[] search = new string[] { "John", "Doe" };
var users = from u in ctx.Users
            from s in search
           where u.FullName.Contains(s)
          select u;

What I want is to find all users where their FullName contains all of the elements in `search'. I've tried a number of different ways, all of which haven't been working for me.

I've also tried

var users = from u in ctx.Users select u;
foreach (string s in search) {
    users = users.Where(u => u.FullName.Contains(s));
}

This version only finds those that contain the last element in the search array.

Лучшее решение, которое я нашел, - это создать в SQL функцию с табличным значением, которая дает результаты, такие как ::

CREATE function [dbo].[getMatches](@textStr nvarchar(50)) returns @MatchTbl table(
Fullname nvarchar(50) null,
ID nvarchar(50) null
)
as begin
declare @SearchStr nvarchar(50);
set @SearchStr = '%' + @textStr + '%';
insert into @MatchTbl 
select (LName + ', ' + FName + ' ' + MName) AS FullName, ID = ID from employees where LName like @SearchStr;
return;
end

GO

select * from dbo.getMatches('j')

Затем вы просто перетаскиваете функцию в свой конструктор LINQ.dbml и вызываете ее так же, как и другие объекты. LINQ даже знает столбцы вашей сохраненной функции. Я называю это так:

Dim db As New NobleLINQ
Dim LNameSearch As String = txt_searchLName.Text
Dim hlink As HyperLink

For Each ee In db.getMatches(LNameSearch)
   hlink = New HyperLink With {.Text = ee.Fullname & "<br />", .NavigateUrl = "?ID = " & ee.ID}
   pnl_results.Controls.Add(hlink)
Next

Невероятно простой и действительно раскрывает всю мощь SQL и LINQ в приложении ... и, конечно же, вы можете сгенерировать любую функцию с табличным значением, какую захотите, для тех же эффектов!

Я считаю, что вы действительно хотите: давайте представим сценарий у вас есть две базы данных и у них есть таблица общих продуктов И вы хотите выбрать продукты из таблицы "A", которая имеет общий идентификатор с "B".

использование метода содержит было бы слишком сложно сделать это то, что мы делаем, является пересечением, и для этого есть метод, называемый пересечением.

пример из msdn: http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#intersect1

int [] числа = (0, 2, 4, 5, 6, 8, 9); int [] numbersB = (1, 3, 5, 7, 8); var = commonNumbers numbersA.Intersect (numbersB);

Я думаю то, что вам нужно, легко решается с помощью пересечения

string[] stringArray = {1,45,20,10};
from xx in table 
where stringArray.Contains(xx.uid.ToString()) 
select xx

Или, если у вас уже есть данные в списке и вы предпочитаете другой формат Linq :)

List<string> uids = new List<string>(){"1", "45", "20", "10"};
List<user> table = GetDataFromSomewhere();

List<user> newTable = table.Where(xx => uids.Contains(xx.uid)).ToList();

LINQ в .NET 4.0 предлагает вам еще один вариант; метод .Any ();

string[] values = new[] { "1", "2", "3" };
string data = "some string 1";
bool containsAny = values.Any(data.Contains);

Отличный ответ, выражения с методами Any() и All() такие простые :) Я могу использовать t => words.All(w => t.Title.Contains(w)).

alcohol is evil 12.01.2017 00:14

from xx in table
where xx.uid.Split(',').Contains(string value )
select xx

Отметьте этот метод расширения:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ContainsAnyProgram
{
    class Program
    {
        static void Main(string[] args)
        {
            const string iphoneAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like...";

            var majorAgents = new[] { "iPhone", "Android", "iPad" };
            var minorAgents = new[] { "Blackberry", "Windows Phone" };

            // true
            Console.WriteLine(iphoneAgent.ContainsAny(majorAgents));

            // false
            Console.WriteLine(iphoneAgent.ContainsAny(minorAgents));
            Console.ReadKey();
        }
    }

    public static class StringExtensions
    {
        /// <summary>
        /// Replicates Contains but for an array
        /// </summary>
        /// <param name = "str">The string.</param>
        /// <param name = "values">The values.</param>
        /// <returns></returns>
        public static bool ContainsAny(this string str, params string[] values)
        {
            if (!string.IsNullOrEmpty(str) && values.Length > 0)
                return values.Any(str.Contains);

            return false;
        }
    }
}

Это поздний ответ, но я считаю, что он все еще полезен.
Я создал пакет nuget NinjaNye.SearchExtension, который может помочь решить эту проблему:

string[] terms = new[]{"search", "term", "collection"};
var result = context.Table.Search(terms, x => x.Name);

Вы также можете искать по нескольким строковым свойствам

var result = context.Table.Search(terms, x => x.Name, p.Description);

Или выполните RankedSearch, который возвращает IQueryable<IRanked<T>>, который просто включает свойство, показывающее, сколько раз появлялись условия поиска:

//Perform search and rank results by the most hits
var result = context.Table.RankedSearch(terms, x => x.Name, x.Description)
                     .OrderByDescending(r = r.Hits);

На странице проектов GitHub есть более подробное руководство: https://github.com/ninjanye/SearchExtensions

Надеюсь, это поможет будущим посетителям

Да, он был специально создан для Entity Framework

NinjaNye 21.12.2016 18:02

Могу ли я использовать это и с методом .Where ()?

Hamza Khanzada 29.03.2020 18:16

Да, он работает на IQueryable и IEnumerable - просто имейте в виду, что если вы подключите его к IEnumerable, он будет работать в памяти, а не создавать запрос и отправлять его источнику.

NinjaNye 31.03.2020 17:24

Метод расширения Linq. Будет работать с любым объектом IEnumerable:

    public static bool ContainsAny<T>(this IEnumerable<T> Collection, IEnumerable<T> Values)
    {
        return Collection.Any(x=> Values.Contains(x));
    }

Использование:

string[] Array1 = {"1", "2"};
string[] Array2 = {"2", "4"};

bool Array2ItemsInArray1 = List1.ContainsAny(List2);

Пытаться:

var stringInput = "test";
var listOfNames = GetNames();
var result = from names in listOfNames where names.firstName.Trim().ToLower().Contains(stringInput.Trim().ToLower());
select names;

Хотя этот код может ответить на вопрос, предоставляя дополнительный контекст относительно как и / или Почему, он решает проблему, что улучшит долгосрочную ценность ответа.

Francesco Menzani 08.08.2015 18:58

Dim stringArray() = {"Pink Floyd", "AC/DC"}
Dim inSQL = From alb In albums Where stringArray.Contains(alb.Field(Of String)("Artiste").ToString())
Select New With
  {
     .Album = alb.Field(Of String)("Album"),
     .Annee = StrReverse(alb.Field(Of Integer)("Annee").ToString()) 
  }

var SelecetdSteps = Context.FFTrakingSubCriticalSteps
             .Where(x => x.MeetingId == meetid)
             .Select(x =>    
         x.StepID  
             );

        var crtiticalsteps = Context.MT_CriticalSteps.Where(x =>x.cropid==FFT.Cropid).Select(x=>new
        {
            StepID= x.crsid,
            x.Name,
            Checked=false

        });


        var quer = from ax in crtiticalsteps
                   where (!SelecetdSteps.Contains(ax.StepID))
                   select ax;

        string texto = "CALCA 40";
        string[] descpart = texto.Split(' ');

        var lst = (from item in db.InvItemsMaster
                   where descpart.All(val => item.itm_desc.Contains(val))
                   select item
                    ).ToList();
        Console.WriteLine("ITM".PadRight(10) + "DESC".PadRight(50)+"EAN".PadRight(14));
        foreach(var i in lst)
        {
           

            Console.Write(i.itm_id.ToString().PadRight(10));
            Console.Write(i.itm_desc.ToString().PadRight(50));
            Console.WriteLine(i.itm_ean.ToString().PadRight(14));


        }

        Console.ReadKey();

Мы приезжаем в SO. Пожалуйста, не давайте ответов «только код». Не могли бы вы добавить объяснение, как это решает проблему и еще не покрыто другими 21 ответами?

marsh-wiggle 20.08.2020 11:16

Другие вопросы по теме