【问题标题】:How do I use LINQ Contains(string[]) instead of Contains(string)如何使用 LINQ Contains(string[]) 而不是 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)

标签: c# linq string contains


【解决方案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 也是 int,List<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() 方法一起使用吗?
                  • 是的,它适用于 IQueryable 和 IEnumerable - 请注意,如果将其链接到 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 个答案尚未涵盖?
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2010-12-29
                        • 2013-12-04
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-08-07
                        相关资源
                        最近更新 更多