大文字と小文字を区別しないリスト検索


144

testList一連の文字列を含むリストがあります。testListリストにまだ存在しない場合にのみ、新しい文字列をに追加したいと思います。したがって、大文字と小文字を区別せずにリストを検索して効率的にする必要があります。Contains大文字・小文字を考慮していないので使用できません。またToUpper/ToLower、パフォーマンス上の理由から使用したくありません。私はこの方法に出会いました、それはうまくいきます:

    if(testList.FindAll(x => x.IndexOf(keyword, 
                       StringComparison.OrdinalIgnoreCase) >= 0).Count > 0)
       Console.WriteLine("Found in list");

これは機能しますが、部分的な単語にも一致します。リストに「山羊」が含まれている場合、「山羊」はすでにリストにあると表示されているため、「山羊」を​​追加できません。大文字と小文字を区別しない方法でリストを効率的に検索する方法はありますか?ありがとう

回答:


180

代わりにString.IndexOfの、使用String.Equalsをあなたは部分一致を持っていないことを確認します。また、すべての要素を通過するため、FindAllを使用しないでください。FindIndexを使用してください(最初にヒットした要素で停止します)。

if(testList.FindIndex(x => x.Equals(keyword,  
    StringComparison.OrdinalIgnoreCase) ) != -1) 
    Console.WriteLine("Found in list"); 

代わりにいくつかのLINQメソッドを使用します(これは、最初にヒットしたメソッドでも停止します)

if( testList.Any( s => s.Equals(keyword, StringComparison.OrdinalIgnoreCase) ) )
    Console.WriteLine("found in list");

加えて、いくつかの簡単なテストでは、最初の方法が約50%高速であるようです。多分誰かがそれを確認/拒否することができます。
BRAP

8
.NET 2.0以降、これは簡単に実行できるようになりました-以下のshaxbyの回答をご覧ください。
ジョー

3
Containsメソッドshaxbyの参照(IEqualityComparerを受け取るオーバーロードを持つ)はLINQの一部であるため、.NET 2.0以降では利用できません。StringComparerクラスだけがしばらくの間存在しています。List <T>にはそのメソッドも、ArrayListやStringCollectionもありません(彼が簡単に「リスト」として参照していた可能性があるもの)。
Adam Sills、2013年

まあ、実際はインデックスが必要だったので、これが間違いなく私にとって最良の答えでした。
Nyerguds 2014年

1
最初のソリューションはList<>.Exists(Predicate<>)インスタンスメソッドを使用する必要があります。また、リストにnullエントリが含まれている場合、これが爆発する可能性があることに注意してください。その場合は(がnullになることがないことが保証できる場合)keyword.Equals(x, StringComparison.OrdinalIgnoreCase)よりも安全です。x.Equals(keyword, StringComparison.OrdinalIgnoreCase)keyword
Jeppe Stig Nielsen

359

これは古い投稿ですが、他の誰かが探している場合に備えて、大文字と小文字を区別しない文字列等価比較子を次のように提供することで使用できますContains

using System.Linq;

// ...

if (testList.Contains(keyword, StringComparer.OrdinalIgnoreCase))
{
    Console.WriteLine("Keyword Exists");
}

msdnによると、これは.net 2.0以降で利用可能です。


21
ここで間違いなく最良の答えです。:)
Joe

22
Enumerable <T> .Contains(参照しているもの)は、.NET 2.0以降存在していません。使用しているオーバーロードを持つList <T> .Containsはありません。
Adam Sills、2013年

@AdamSillsそうです。List <T>にはそのようなcontainsメソッドはありません。そして、それが遅延コレクションの場合は、他のEnumerable <T>メソッドと同じように、数回繰り返すことができます。Imho、このメソッドはそのようなケースではあまり論理的ではないため、そのようなケースでは使用しないでください。
Sergey Litvinov

40
最初はこのオーバーロードも表示されませんでしたが、System.Linqを使用して追加する必要があります。
マイケル

1
StringComparerクラスは2.0以来の周りされているが、含まれているの過負荷は3.5で導入されました。 msdn.microsoft.com/en-us/library/bb339118(v=vs.110).aspx
Denise Skidmore

18

上記のAdam Sillsの回答に基づく-以下は、Containsのクリーンな拡張メソッドです... :)

///----------------------------------------------------------------------
/// <summary>
/// Determines whether the specified list contains the matching string value
/// </summary>
/// <param name="list">The list.</param>
/// <param name="value">The value to match.</param>
/// <param name="ignoreCase">if set to <c>true</c> the case is ignored.</param>
/// <returns>
///   <c>true</c> if the specified list contais the matching string; otherwise, <c>false</c>.
/// </returns>
///----------------------------------------------------------------------
public static bool Contains(this List<string> list, string value, bool ignoreCase = false)
{
    return ignoreCase ?
        list.Any(s => s.Equals(value, StringComparison.OrdinalIgnoreCase)) :
        list.Contains(value);
}

10

StringComparerを使用できます。

    var list = new List<string>();
    list.Add("cat");
    list.Add("dog");
    list.Add("moth");

    if (list.Contains("MOTH", StringComparer.OrdinalIgnoreCase))
    {
        Console.WriteLine("found");
    }

1
"using System.Linq"を追加する限り、そうでなければ.Containsのオーバーロードは表示されません。
ジュリアンメルビル

1

Lance Larsenの回答に基づく-これは、推奨されるstring.Compareの代わりにstring.Equalsを使用した拡張メソッドです

StringComparisonパラメーターを受け取るString.Compareのオーバーロードを使用することを強くお勧めします。これらのオーバーロードを使用すると、意図した正確な比較動作を定義できるだけでなく、それらを使用すると、他の開発者がコードを読みやすくなります。[ Josh Free @ BCLチームのブログ ]

public static bool Contains(this List<string> source, string toCheck, StringComparison comp)
{
    return
       source != null &&
       !string.IsNullOrEmpty(toCheck) &&
       source.Any(x => string.Compare(x, toCheck, comp) == 0);
}

0

IndexOfの結果が0以上であるかどうか、つまり、文字列のどこからでも一致が始まるかどうかを確認しています。それが0に等しいかどうかを確認してください。

if (testList.FindAll(x => x.IndexOf(keyword, 
                   StringComparison.OrdinalIgnoreCase) >= 0).Count > 0)
   Console.WriteLine("Found in list");

現在、「ヤギ」と「オート」は一致しませんが、「ヤギ」と「ゴア」は一致します。これを回避するには、2つの文字列の長さを比較します。

このすべての複雑さを回避するために、リストの代わりに辞書を使用できます。キーは小文字の文字列で、値は実際の文字列です。この方法では、ToLower比較ごとにを使用する必要がないため、パフォーマンスは低下しませんが、を使用できますContains


0

以下は、リスト全体でキーワードを検索してその項目を削除する例です。

public class Book
{
  public int BookId { get; set; }
  public DateTime CreatedDate { get; set; }
  public string Text { get; set; }
  public string Autor { get; set; }
  public string Source { get; set; }
}

Textプロパティにキーワードが含まれている本を削除する場合は、キーワードのリストを作成して、本のリストから削除できます。

List<Book> listToSearch = new List<Book>()
   {
        new Book(){
            BookId = 1,
            CreatedDate = new DateTime(2014, 5, 27),
            Text = " test voprivreda...",
            Autor = "abc",
            Source = "SSSS"

        },
        new Book(){
            BookId = 2,
            CreatedDate = new DateTime(2014, 5, 27),
            Text = "here you go...",
            Autor = "bcd",
            Source = "SSSS"


        }
    };

var blackList = new List<string>()
            {
                "test", "b"
            }; 

foreach (var itemtoremove in blackList)
    {
        listToSearch.RemoveAll(p => p.Source.ToLower().Contains(itemtoremove.ToLower()) || p.Source.ToLower().Contains(itemtoremove.ToLower()));
    }


return listToSearch.ToList();

-1

同様の問題があり、アイテムのインデックスが必要でしたが、大文字と小文字を区別しなければなりませんでした。数分間Webを見回しても何も見つからなかったので、それを実行するための小さなメソッドを作成しただけです。した:

private static int getCaseInvariantIndex(List<string> ItemsList, string searchItem)
{
    List<string> lowercaselist = new List<string>();

    foreach (string item in ItemsList)
    {
        lowercaselist.Add(item.ToLower());
    }

    return lowercaselist.IndexOf(searchItem.ToLower());
}

このコードを同じファイルに追加し、次のように呼び出します。

int index = getCaseInvariantIndexFromList(ListOfItems, itemToFind);

これがお役に立てば幸いです。


1
なぜ2番目のリストを作成するのですか?それはあまり効率的ではありません。for(var i = 0; i <itemsList.Count; i ++){if(item.ToLower()== searchItem.ToLower()){return i}}
wesm

私たちは決して知ることはないと思います。
デニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.