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


103

我有一个大问题。

我得到了一个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可能看起来像什么,以及什么将被视为匹配。
James Curran

3
一个例子会很好。在我看来,这个问题是在询问UID,例如:CA1FAB689C33和以下数组:{“ 42”,“ 2259”,“ CA”}
Thomas Bratt

3
相反的说法更有意义:string []。Contains(xx.uid)
majkinetor 2010年

Answers:


86

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

[编辑]

除非您string[]按照Mitch Wheat的演示进行更改和编写,否则您将只能跳过转换步骤。

[ENDEDIT]

这就是您想要的,如果您不执行扩展方法(除非您已经将潜在的uid的集合作为int -而是使用它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,

4
根据MSDN,string []实现IEnumerable <T>,该方法具有Contains方法。因此,没有必要将数组转换为IList <T>。 msdn.microsoft.com/en-us/library/19e6zeyy.aspx
Spoulson

最后一个.ToString()为我抛出错误。具体来说,LINQ to Entities无法识别方法'System.String ToString()',并且该方法无法转换为商店表达式...。删除它之后,lambda为我工作。
Sam Stange

我喜欢这个,它是如此简单,以至于我都不记得了。
Olaj 2011年

@SamStange-LINQ的一个问题是变量太多,抽象是“泄漏的”,有时您需要知道要使用哪个变量才能正确构建查询。如所写,这将适用于LINQ对象(也可能是LINQ to SQL)。对于EF,您可以采用另一种方法,将其构造在内存中,List<int>而不是跳过该ToString调用。
tvanfosson

36

如果您确实要复制Contains,但要复制数组,请使用以下扩展方法和示例代码:

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

2
+1 @Jason,您应该将其完全提交给ExtensionMethod.net。 感谢出色的代码,它今天解决了我的问题!
p.campbell,

4
我认为您的意思是!string.IsNullOrEmpty(str)&& values.Length> 0
Greg Bogumil 2010年

你是对的。我进行了更改,尽管它没有功能上的影响。我在工作中使用了这样的功能。我将不得不检查!
杰森·杰克逊

@JasonJackson我意识到这已经很老了,但是(如Greg所提到的),在这种条件下,您是否不想要“也可以”而不是“否则”?
Tieson T.

@TiesonT。条件条件“或其他”和“以及也”都将以该函数返回的结果相同。如果!string.IsNullOrEmpty(str)检查通过,导致values.Length > 0条件被忽略,但Values的长度为0,则它将转到foreach,然后立即中断,因为数组中没有条目,直接转到return false
Meowmaritus

20

尝试以下方法。

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

2
我真的希望人们在您打败您时留下评论。特别是由于我提供的答案是100%正确的。
JaredPar

不是我,但是All()不会仅仅返回布尔值来指示所有项目都符合条件的地方吗?并将toSearchFor初始化为null可以保证NullReferenceException。
卢卡斯

我将null问题编辑为要输入的内容。是的。这有效地确保了toSearchFor中的所有字符串都包含在输入字符串中。
JaredPar

6
我完全看不出这是如何回答问题的。这个问题变了吗?
tvanfosson

15

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

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

1
好的答案,带有Any()All()方法的表达式非常简单:)我可以使用t => words.All(w => t.Title.Contains(w))
酒精是邪恶的

7

或者,如果您已经在列表中包含数据,并且希望使用其他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();

3

怎么样:

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

NotSupportedException:类型'System.String []'不支持比较运算符谢谢,然后重试?
SpoiledTechie.com

+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;
        }
    }
}

1
与public static bool Contains(this string [] stringarray,string pat)相同{return Array.IndexOf(stringarray,pat)!= -1; }
James Curran

5
string []实现IEnumerable <string>,因此它已经具有Contains(string)扩展方法。我们为什么要重新实现呢?
卢卡斯

2

这是一个较晚的答案,但我相信它仍然有用
我创建了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<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

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


1
是的,它是专门针对实体框架而设计的
NinjaNye

1
我也可以将其与.Where()方法一起使用吗?
Hamza Khanzada

是的,它可以工作,IQueryable而且IEnumerable-如果您将其链接到IEnumerable,它将不为所动,而会运行在内存中,而不是构建查询并将其发送给源代码
NinjaNye

2

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

1

我相信您也可以这样做。

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

与“ where stringArray.Contains(xx.uid.ToString())”相同,无需在查询中将其换行
Lucas

0

所以我是否正确假设uid是唯一标识符(Guid)?这只是可能情况的一个示例,还是您真的在尝试寻找与字符串数组匹配的GUID?

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

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

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


0

您应该用另一种方式编写它,检查特权用户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'

基本上将“搜索”数组的内容嵌入到SQL查询中,并在SQL中使用“ IN”关键字进行过滤。


只要您没有2100个以上的参数,此方法就可以正常工作。
jpierson

0

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

我想要的是找到所有用户的FullName包含“搜索”中的所有元素。我尝试了许多不同的方法,但所有这些方法都不适合我。

我也尝试过

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

此版本仅查找那些包含搜索数组中最后一个元素的元素。


0

我发现最好的解决方案是继续在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在应用程序中的强大功能……您当然可以生成想要达到相同效果的任何表值函数!


0

我相信您真正想做的是:假设有两个数据库,并且它们有一个共同的产品表,而您想从ID与“ B”共同的表“ A”中选择产品

使用contains的方法来完成此操作太复杂了,我们正在做的是一个交集,为此有一种称为交集的方法

来自msdn的示例:http : //msdn.microsoft.com/zh-cn/vcsharp/aa336761.aspx#intersect1

int []数字=(0、2、4、5、6、8、9);int []数字B =(1、3、5、7、8);var = commonNumbers numbersA.Intersect(numbersB);

我认为您需要的东西很容易用十字路口解决


0

检查此扩展方法:

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

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

0

尝试:

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 2015年

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

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

我们来吧。请不要给出“仅代码”答案。您能否添加一些解释,说明这是如何解决问题的,而其他21个答案尚未涵盖?
marsh-wiggle

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

-2
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()) 
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.