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.