Contains (string) 대신 LINQ 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
예가 좋을 것입니다. 질문이 CA1FAB689C33과 같은 UID를 요청하는 것처럼 들립니다. 배열은 다음과 같습니다. { "42", "2259", "CA"}
Thomas Bratt

3
반대는 더 의미가 있습니다 : 문자열 [] (xx.uid)이 포함되어 있습니다.이
majkinetor

답변:


87

spoulson 거의 바로 그것을 가지고 있지만, 당신은 만들어야 List<string>에서 string[]첫번째. 실제로 List<int>uid가이면 a 가 더 좋습니다 int. List<T>지원합니다 Contains(). 이렇게 uid.ToString().Contains(string[])문자열로 UID가 문자열로 배열의 값이 모두 포함되어 있음을 암시 ??? 확장 방법을 작성했다고해도 그 의미는 틀릴 것입니다.

[편집하다]

string[]Mitch Wheat가 설명 하는 대로 변경하여 작성하지 않는 한 변환 단계를 건너 뛸 수 있습니다.

[종료]

확장 메서드를 사용하지 않는 경우 원하는 것은 다음과 같습니다 (이미 int로 잠재적 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

4
MSDN에 따르면 string []은 Contains 메서드가있는 IEnumerable <T>를 구현합니다. 따라서 배열을 IList <T>로 변환 할 필요가 없습니다. msdn.microsoft.com/en-us/library/19e6zeyy.aspx
spoulson

마지막 .ToString ()은 나를 위해 오류를 발생시킵니다. 특히 LINQ to Entities는 'System.String ToString ()'메서드를 인식하지 못하며이 메서드는 저장소 식으로 변환 할 수 없습니다 .... 제거 후 람다가 저에게 효과적이었습니다.
Sam Stange 2011 년

나는 이것을 좋아합니다. 너무 쉬워서 결코 기억하지 못합니다.
Olaj

@SamStange-LINQ의 한 가지 문제는 변형이 너무 많고 추상화가 "누수"라는 것입니다. 쿼리를 제대로 구성하기 위해 어떤 변형을 사용하는지 알아야 할 때가 있습니다. 작성된대로 이것은 LINQ to 개체에 대해 작동합니다 (LINQ to SQL 일 수 있음). EF의 경우 다른 방식으로 수행하고 List<int>대신 메모리에 컬렉션을 구성 하고 ToString호출을 건너 뜁니다 .
tvanfosson 2011 년

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을 의미 생각
그렉 Bogumil을

당신이 옳습니다. 기능적 영향은 없지만 변경했습니다. 나는 직장에서 이와 같은 기능을 사용합니다. 나는 그것을 확인해야 할 것이다!
Jason Jackson

@JasonJackson 나는 이것이 오래되었다는 것을 알고 있지만 (그렉이 언급했듯이) 그 조건부에서 "또는 다른"보다는 "또한"를 원하지 않습니까?
Tieson T. 2015 년

@TiesonT. "or else"와 "and also"조건문은 모두 함수에서 반환 된 동일한 결과로 끝납니다. 경우 !string.IsNullOrEmpty(str)검사가 통과의 원인이 values.Length > 0조건은 무시합니다, 하지만 값의 길이는 0이었다 다음은에 갈 것입니다, foreach그리고로 직접 이동 배열에 항목이 없기 때문에 즉시 중단 return false.
Meowmaritus

20

다음을 시도하십시오.

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

2
나는 사람들이 당신을 표시 할 때 댓글을 남기기를 정말로 바랍니다. 특히 제가 제공 한 답변이 100 % 정확하기 때문에.
JaredPar

내가 아니었지만 All ()은 모든 항목이 조건과 일치하는 위치를 나타내는 bool을 단순히 반환하지 않습니까? 그리고 toSearchFor를 null로 초기화하면 NullReferenceException이 보장됩니다.
Lucas

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, 이것이 실제로 그들이 원하는 것이라면. 질문에서 명확하지 않습니다.
Lucas

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) 확장 메서드가 있습니다. 우리가 이것을 다시 구현하는 이유는 무엇입니까?
Lucas

2

이것은 늦은 답변이지만 여전히 유용하다고 생각합니다 . 이 문제를 해결하는 데 도움이
되는 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);

또는 검색어가 표시된 횟수를 표시하는 속성을 포함 하는 RankedSearchwhich 반환 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
예, Entity Framework를 대상으로 특별히 제작되었습니다
NinjaNye

1
.Where () 메서드와 함께 사용할 수 있습니까?
Hamza Khanzada

네, 그것은 작동 IQueryable하고 IEnumerable- 당신은 IEnumerable을 떨어져 그것을 체인 경우,이 memeory에서 실행하기보다는 쿼리를 작성하고 소스에 내려 보내는됩니다 awayre 일
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

"여기서 stringArray.Contains (xx.uid.ToString ())"필요가 쿼리에 주위에 감아하는 동일
루카스

0

그렇다면 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의 숫자 순서를 보장하지 않으므로 잠재적으로 여러 항목을 일치시킬 수 있습니다. 이러한 방식으로 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 2013 년

0

나는 해결책을 찾을 수 있었지만 DB에서 모든 결과를 반환하는 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/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);

필요한 것은 교차로로 쉽게 해결할 수 있다고 생각합니다


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

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 개의 답변에서 아직 다루지 않았습니까?
습지 흔들기

-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()) 
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.