У меня есть один большой вопрос.
Я получил запрос 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, например: CA1FAB689C33, и массив, например: {"42", "2259", "CA"}
Противоположное имеет больше смысла: строка []. Содержит (xx.uid)





Как насчет:
from xx in table
where stringarray.Contains(xx.uid.ToString())
select xx
NotSupportedException: операторы сравнения не поддерживаются для типа System.String []. Спасибо, но попробуйте еще раз?
+1, если они действительно этого хотят. Не очень понятно из вопроса.
Это пример одного из способов написания метода расширения (примечание: я бы не стал использовать его для очень больших массивов; более подходящей была бы другая структура данных ...):
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; }
string [] реализует IEnumerable <string>, поэтому у него уже есть метод расширения Contains (string). Почему мы перерабатываем это?
Я считаю, что вы тоже могли бы сделать что-то подобное.
from xx in table
where (from yy in string[]
select yy).Contains(xx.uid.ToString())
select xx
То же, что и «where stringArray.Contains (xx.uid.ToString ())», нет необходимости оборачивать его в запросе
Споулсон почти прав, но сначала вам нужно создать 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. В любом случае, вы могли бы свести оба оператора к одному запросу из базы данных?
Согласно MSDN, string [] реализует IEnumerable <T>, который имеет метод Contains. Следовательно, нет необходимости преобразовывать массив в IList <T>. msdn.microsoft.com/en-us/library/19e6zeyy.aspx
Последний .ToString () вызывает у меня ошибки. В частности, LINQ to Entities не распознает метод System.String ToString (), и этот метод не может быть преобразован в выражение хранилища .... После его удаления лямбда сработала для меня.
Мне это нравится, это так просто, что я никогда этого не помню.
@SamStange - одна проблема с LINQ заключается в том, что существует так много вариантов, а абстракция «дырявая», вам иногда нужно знать, какой вариант вы используете, чтобы правильно построить запрос. Как написано, это будет работать для LINQ to objects (и может быть LINQ to SQL). Для EF вы должны сделать это наоборот и вместо этого создать коллекцию в памяти как List<int> и пропустить вызов ToString.
HashSet будет еще быстрее
@Blam, если только это не запрос, который конвертируется в SQL, что, я думаю, было контекстом в то время.
Попробуйте следующее.
string input = "someString";
string[] toSearchFor = GetSearchStrings();
var containsAll = toSearchFor.All(x => input.Contains(x));
Я действительно хочу, чтобы люди оставляли комментарии, когда отмечали вас. Тем более, что ответ, который я дал, верен на 100%.
Это был не я, но разве All () не возвращает просто логическое значение, указывающее, где все элементы соответствуют условию? И инициализация toSearchFor нулевым значением гарантирует исключение NullReferenceException.
Я отредактировал нулевую проблему так, чтобы она соответствовала тому, что собиралась ввести. Да на всех. Это эффективно гарантирует, что все строки в toSearchFor содержатся во входной строке.
Я вообще не понимаю, как это отвечает на вопрос. Вопрос изменился на вас?
Если вы действительно хотите реплицировать Содержит, но для массива, вот метод расширения и пример кода для использования:
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 Спасибо за отличный код, он решил мою проблему сегодня!
Я думаю, вы имели в виду! String.IsNullOrEmpty (str) && values.Length> 0
Ты прав. Я его поменял, но функционального влияния не оказывает. Я использую такую функцию на работе. Придется это проверить!
@JasonJackson Я понимаю, что это старый (иш), но (как сказал Грег) разве вы не хотите, чтобы в этом условном выражении было «а также», а не «или еще»?
@TiesonT. И «or else», и «and also» в конечном итоге приведут к одному и тому же результату, возвращаемому функцией; если проверка !string.IsNullOrEmpty(str) пройдена, в результате чего условие values.Length > 0 будет проигнорировано, но длина значений была 0, тогда он перейдет к foreach, а затем немедленно прервется, потому что в массиве нет записей, перейдя непосредственно к return false.
@ GreenCat77 Это правда, но зачем вообще зацикливаться, если в value нет элементов?
Наконец, пример, показывающий, как искать строки массива в другой строке.
Грег Богумил прав, это должно быть && не || в операторе if. В противном случае первая проверка бессмысленна, если values не пуст.
Итак, правильно ли я предполагаю, что 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 параметров.
Мне удалось найти решение, но не лучшее, поскольку для этого требуется использовать 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)).
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);
Надеюсь, это поможет будущим посетителям
Да, он был специально создан для Entity Framework
Могу ли я использовать это и с методом .Where ()?
Да, он работает на IQueryable и IEnumerable - просто имейте в виду, что если вы подключите его к IEnumerable, он будет работать в памяти, а не создавать запрос и отправлять его источнику.
Метод расширения 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;
Хотя этот код может ответить на вопрос, предоставляя дополнительный контекст относительно как и / или Почему, он решает проблему, что улучшит долгосрочную ценность ответа.
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 ответами?
Вам необходимо уточнить, как будет выглядеть uid и что будет считаться совпадением.