如何使用 LINQ Contains(string[]) 而不是 Contains(string)

Posted

技术标签:

【中文标题】如何使用 LINQ Contains(string[]) 而不是 Contains(string)【英文标题】:How do I use LINQ Contains(string[]) instead of Contains(string) 【发布时间】:2010-09-16 17:35:51 【问题描述】:

我有一个大问题。

我得到了一个 linq 查询,简单来说就是这样:

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

string[] 数组的值可以是 (1,45,20,10,etc...) 之类的数字

.Contains 的默认值为 .Contains(string)

我需要它来代替:.Contains(string[])...

编辑:一位用户建议为string[] 编写一个扩展类。我想学习如何,但有人愿意为我指明正确的方向吗?

编辑: uid 也是一个数字。这就是它被转换为字符串的原因。

帮助任何人?

【问题讨论】:

您需要澄清 uid 可能看起来像什么,以及什么会被视为匹配项。 举个例子就好了。在我看来,问题是要求一个 UID,例如:CA1FAB689C33 和数组:“42”、“2259”、“CA” 相反更有意义:string[].Contains(xx.uid) 【参考方案1】:

怎么样:

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

【讨论】:

NotSupportedException: 类型'System.String[]'不支持比较运算符 谢谢但再试一次? +1,如果这确实是他们想要的。问题不是很清楚。【参考方案2】:

这是一种编写扩展方法的示例(注意:我不会将它用于非常大的数组;另一种数据结构会更合适...):

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;
        
    

【讨论】:

等同于 public static bool Contains(this string[] stringarray, string pat) return Array.IndexOf(stringarray, pat) != -1; string[] 实现了 IEnumerable,所以它已经有了 Contains(string) 扩展方法。我们为什么要重新实现它?【参考方案3】:

我相信你也可以这样做。

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

【讨论】:

与“where stringArray.Contains(xx.uid.ToString())”相同,不需要在查询中环绕【参考方案4】:

spoulson 几乎是正确的,但您需要先从string[] 创建一个List<string>。实际上,如果 uid 也是 intList<int> 会更好。 List<T> 支持 Contains()。执行uid.ToString().Contains(string[]) 意味着作为字符串的 uid 包含作为子字符串的数组的所有值???即使您确实编写了扩展方法,它的感觉也是错误的。

[编辑]

除非像 Mitch Wheat 演示的那样更改它并为 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,它有一个 Contains 方法。因此,不必将数组转换为 IList。 msdn.microsoft.com/en-us/library/19e6zeyy.aspx 最后一个 .ToString() 为我抛出错误。具体来说,LINQ to Entities 无法识别方法 'System.String ToString()' 方法,并且该方法无法转换为存储表达式....删除它后,lambda 为我工作。 我喜欢这个,它太简单了以至于我都不记得了。 @SamStange - LINQ 的一个问题是有这么多变体并且抽象是“泄漏的”,有时您需要知道您正在使用哪个变体才能正确构造查询。正如所写,这适用于 LINQ to 对象(并且可能是 LINQ to SQL)。对于 EF,您可以反其道而行之,将内存中的集合构造为 List<int>,然后跳过 ToString 调用。【参考方案5】:

试试下面的。

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

【讨论】:

我真的希望人们在标记你时留下评论。特别是因为我提供的答案是 100% 正确的。 不是我,但 All() 不是简单地返回一个布尔值,指示所有项目在哪里符合条件吗?并将 toSearchFor 初始化为 null 保证 NullReferenceException。 我将 null 问题编辑为我想要输入的内容。是的。这有效地确保了 toSearchFor 中的所有字符串都包含在输入字符串中。 我根本不明白这是如何回答这个问题的。这个问题对你有影响吗?【参考方案6】:

如果您真的想复制 包含,但对于数组,这里有一个 extension method 和示例代码供使用:

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 我意识到这是旧的(ish),但是(正如格雷格所提到的)你不想要一个“and also”而不是那个条件中的“or else”吗? @TiesonT。 "or else" 和 "and Also" 条件句最终都会得到函数返回的相同结果;如果!string.IsNullOrEmpty(str)检查通过,导致values.Length > 0条件被忽略,但Values的长度为0,那么它会转到foreach然后立即中断,因为没有数组中的条目,直接转到return false【参考方案7】:

那么我是否正确地假设 uid 是唯一标识符 (Guid)?这只是可能场景的一个示例,还是您真的试图找到与字符串数组匹配的 guid?

如果这是真的,您可能需要重新考虑整个方法,这似乎是一个非常糟糕的主意。您可能应该尝试将 Guid 与 Guid 匹配

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

老实说,我无法想象使用“包含”将字符串数组与 Guid 的内容进行匹配会是一个好主意。一方面, Contains() 不会保证 Guid 中的数字顺序,因此您可能会匹配多个项目。更不用说以这种方式比较 guid 会比直接进行比较慢。

【讨论】:

【参考方案8】:

你应该反过来写,检查你的特权用户 id 列表是否包含表中那一行的 id:

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查询中,并在SQL中使用'IN'关键字进行过滤。

【讨论】:

只要您的参数不超过 2100 个,此方法就可以正常工作。【参考方案9】:

我设法找到了一个解决方案,但不是一个很好的解决方案,因为它需要使用 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;

我的原帖如下:

你如何做相反的事情?我想要 执行以下操作 实体框架。

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

我想要的是找到所有用户 他们的全名包含所有 “搜索”中的元素。我试过一个 多种不同的方式,所有这些 没有为我工作。

我也试过

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

这个版本只找到那些 包含搜索中的最后一个元素 数组。

【讨论】:

【参考方案10】:

我找到的最佳解决方案是继续在 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 的强大功能......当然,您可以生成任何您想要的表值函数以获得相同的效果!

【讨论】:

【参考方案11】:

我相信你真正想做的是: 让我们想象一个场景 你有两个数据库 他们有一张共同的产品表 并且您想从表“A”中选择 id 与“B”相同的产品

使用方法 contains 太复杂了,无法做到这一点 我们正在做的是一个交集,并且有一个方法叫做交集

来自 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);

我认为你需要的东西很容易通过交集来解决

【讨论】:

【参考方案12】:
string[] stringArray = 1,45,20,10;
from xx in table 
where stringArray.Contains(xx.uid.ToString()) 
select xx

【讨论】:

【参考方案13】:

或者,如果您已经将数据放在列表中并且更喜欢其他 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();

【讨论】:

【参考方案14】:

.NET 4.0 中的 LINQ 为您提供了另一种选择; .Any() 方法;

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

【讨论】:

很好的答案,Any()All() 方法的表达式非常简单 :) 我可以使用 t =&gt; words.All(w =&gt; t.Title.Contains(w))【参考方案15】:
from xx in table
where xx.uid.Split(',').Contains(string value )
select xx

【讨论】:

【参考方案16】:

检查这个扩展方法:

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;
        
    

【讨论】:

【参考方案17】:

这是一个迟到的答案,但我相信它仍然有用。 我创建了NinjaNye.SearchExtension nuget 包,可以帮助解决这个问题。:

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&lt;IRanked&lt;T&gt;&gt;,它只包含一个显示搜索词出现次数的属性:

//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

希望这对未来的访客有所帮助

【讨论】:

是的,它是专门针对实体框架构建的 我可以将它与 .Where() 方法一起使用吗? 是的,它适用于 IQueryableIEnumerable - 请注意,如果将其链接到 IEnumerable,它将在内存中运行,而不是构建查询并将其发送到来源【参考方案18】:

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);

【讨论】:

【参考方案19】:

试试:

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

【讨论】:

虽然此代码可以回答问题,但提供有关 如何 和/或 为什么 解决问题的附加上下文将改善答案的长期价值。【参考方案20】:
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()) 
  

【讨论】:

【参考方案21】:
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;

【讨论】:

【参考方案22】:
        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 个答案尚未涵盖?

以上是关于如何使用 LINQ Contains(string[]) 而不是 Contains(string)的主要内容,如果未能解决你的问题,请参考以下文章

Linq:int类型使用Contains方法

无法通过 Linq 方法 Contains() 针对 char 数组检查字符串,因为该数组不是 String 类型,转换为 String 类型失败

如何使用 LINQ Contains() 查找枚举列表?

LINQ .Startswith 或 .Contains VB.NET4 中的问题

使用 LINQ 包含 - 如何确保不跟随特定字符

linq All,Any,Contains,自定义比较器