Contains(string)の代わりにLINQ Contains(string [])を使用する方法


103

大きな質問が一つありました。

私はそれを置くためのlinqクエリを単純に次のように取得しました:

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

string[]配列の値は(1,45,20,10など)のような数値になります。

デフォルトは.Containsです.Contains(string)

代わりにこれを行う必要があります: .Contains(string[])...

編集: 1人のユーザーがの拡張クラスを作成することを提案しましたstring[]。方法を学びたいのですが、私を正しい方向に向けてくれる人はいますか?

編集: uidも数字になります。それが文字列に変換される理由です。

誰か助けて?


uidがどのように見えるか、および一致と見なされるものを明確にする必要があります。
James Curran、

3
例がいいでしょう。質問は次のようなUIDを要求しているように聞こえます:CA1FAB689C33および次のような配列:{"42"、 "2259"、 "CA"}
Thomas Bratt

3
反対の方が理にかなっています:string []。Contains(xx.uid)
majkinetor

回答:


86

spoulsonはほぼ正しいですがList<string>string[]最初にfrom を作成する必要があります。実際にList<int>はuidもあると良いでしょうintList<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));

ありがとうございました。それは正解でした...もう1つ考えましたか?arrayuidsもlinqクエリであるとしましょう。両方のステートメントをデータベースから1つのクエリにまとめる方法はありますか?
SpoiledTechie.com 2008年

4
MSDNによると、string []は、Containsメソッドを持つIEnumerable <T>を実装しています。したがって、配列をIList <T>に変換する必要はありません。 msdn.microsoft.com/en-us/library/19e6zeyy.aspx
スポールソン2008年

最後の.ToString()は私にエラーをスローします。具体的には、LINQ to Entitiesはメソッド 'System.String ToString()'メソッドを認識せず、このメソッドはストア式に変換できません...削除した後、ラムダが機能しました。
Sam Stange 2011

私はこれが大好きです。とても簡単なので、覚えていません。
オラジ、2011

@SamStange-LINQの1つの問題は、非常に多くのバリアントがあり、抽象化が「リーキー」であることです。クエリを適切に構築するために、使用しているバリアントを知る必要がある場合があります。書かれているように、これは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 @ジェイソン、ExtensionMethod.netにこれを完全に送信する必要があります。 すばらしいコードをありがとう、それは今日私の問題を解決しました!
p.campbell 2009年

4
string!IsNullOrEmpty(str)&& values.Length> 0
Greg Bogumil

あなたが正しいです。機能的な影響はありませんが、変更しました。このような機能を仕事で使っています。要チェックです!
ジェイソンジャクソン

@JasonJackson私はこれが古い(ish)であることに気づきましたが、(Gregが述べたように)その条件で「またはその他」ではなく「およびその他」が必要ではありませんか?
Tieson T.

@TiesonT。「or else」と「and also」の両方の条件は、関数から返される同じ結果になります。場合は!string.IsNullOrEmpty(str)、チェックが原因、渡されたvalues.Length > 0条件が無視されるように、しかし、値の長さが0だった、それはに行くだろうforeachし、その後、アレイにエントリはに直接行く、存在しないため、すぐに壊れますreturn false
Meowmaritus 2017

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

6
これがどのように質問に答えるかはわかりません。質問はあなたにモーフィングしましたか?
tvanfosson 2015

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

+1、これが実際に必要な場合。質問からはあまり明確ではありません。
ルーカス、

2

これは、拡張メソッドを作成する1つの方法の例です(注:非常に大きな配列には使用しません。別のデータ構造の方が適切です...)。

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
はい、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

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

正直に言って、「contains」を使用して文字列配列をGuidのコンテンツに一致させることが良い考えであるシナリオは想像できません。1つには、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'

これは基本的に 'search'配列の内容をsqlクエリに埋め込み、SQLで 'IN'キーワードを使用してフィルタリングを行います。


2100を超えるパラメーターがない限り、これは問題なく機能します。
jpierson 2013

0

私はなんとか解決策を見つけましたが、DBからすべての結果を返すAsEnumerable()を使用する必要があるため、優れた解決策ではありませんでした。 。

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に「search」のすべての要素が含まれているすべてのユーザーを検索する必要があります。私はさまざまな方法を試しましたが、どれもうまくいきませんでした。

私も試しました

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

私はあなたが本当にやりたいことは次のとおりだと思います:2つのデータベースがあり、それらに共通の製品のテーブルがあるシナリオを想像してみてください

メソッド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

試してください:

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;

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