대소 문자를 구분하지 않는 목록 검색


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의 답변을보십시오.
— Joe

3
Contains 메소드 shaxby의 참조 (IEqualityComparer를 사용하는 과부하가 있음)는 LINQ의 일부이므로 .NET 2.0 이후에는 사용할 수 없었습니다. StringComparer 클래스는 잠시 동안 사용되었습니다. List <T>에는 해당 메소드가 없으며 ArrayList 또는 StringCollection ( '자신의'목록 '으로 쉽게 참조 할 수있는 것)도 없습니다.
— Adam Sills 2016 년

글쎄, 실제로 색인이 필요 했기 때문에 이것은 나에게 가장 좋은 대답이었습니다.
— Nyerguds

1
첫 번째 솔루션은 List<>.Exists(Predicate<>)인스턴스 메소드를 사용해야 합니다. 또한 목록에 null항목이 포함되어 있으면 문제가 발생할 수 있습니다. 이 경우 ( null을 절대로 보장 하지 않는 경우) keyword.Equals(x, StringComparison.OrdinalIgnoreCase)보다 말하는 것이 더 안전합니다 . x.Equals(keyword, StringComparison.OrdinalIgnoreCase)keyword
— Jeppe Stig Nielsen

360

나는 이것이 오래된 게시물이라는 것을 알고 있지만 다른 사람이 찾고 있는 경우를 대비하여 대소 문자를 구분하지 않는 문자열 동등 비교기를 제공하여 사용할 수 있습니다 Contains.

using System.Linq;

// ...

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

이것은 msdn 에 따라 .net 2.0부터 사용 가능 합니다.


21
확실히 최고의 답변입니다. :)
— Joe

22
Enumerable <T>. .NET 2.0 이후에는 (참조하는 내용)이 포함되어 있지 않습니다. 사용중인 과부하가있는 List <T>가 없습니다.
— Adam Sills

@AdamSills 맞습니다. List <T>에는 그러한 포함 메소드가 없습니다. 그리고 게으른 컬렉션이라면 다른 Enumerable <T> 메서드처럼 몇 번 반복 할 수 있습니다. Imho,이 방법은 그 경우에는 논리적이지 않기 때문에 그러한 경우에는 사용해서는 안됩니다.
— 세르게이 Litvinov

40
처음에는이 과부하를 보지 못했지만 System.Linq를 사용하여 추가해야합니다.
— Michael

1
StringComparer클래스는 2.0 이후 주변왔다,하지만 포함의 과부하은 3.5에서 소개되었습니다. msdn.microsoft.com/ko-kr/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
"System.Linq 사용"을 추가하지 않으면 .Contains에 대한 과부하가 표시되지 않습니다.
— Julian Melville

1

랜스 라슨 (Lance Larsen) 답변을 기반으로-권장 문자열이있는 확장 방법이 있습니다. 문자열 대신 비교하십시오.

StringComparison 매개 변수를 사용하는 String.Compare의 오버로드를 사용하는 것이 좋습니다. 이러한 오버로드를 통해 의도 한 정확한 비교 동작을 정의 할 수있을뿐만 아니라이를 사용하면 다른 개발자가 코드를보다 쉽게 ​​읽을 수 있습니다. [ 조쉬 프리 @ 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");

이제 "염소"와 "귀리"는 일치하지 않지만 "염소"와 "고아"는 일치합니다. 이를 피하기 위해 두 줄의 길이를 비교할 수 있습니다.

이 모든 합병증을 피하기 위해 목록 대신 사전을 사용할 수 있습니다. 키는 소문자 문자열이고 값은 실제 문자열입니다. 이렇게하면 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

비슷한 문제가 있었지만 항목의 색인이 필요했지만 대소 문자를 구분하지 않아야했습니다. 몇 분 동안 웹을 둘러 보았고 아무것도 발견하지 못했습니다. 그래서 작은 방법을 작성하여 완료했습니다. 했다 :

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
왜 두 번째 목록을 생성합니까? 그다지 효율적이지 않습니다. for (var i = 0; i <itemsList.Count; i ++) {if (item.ToLower () == searchItem.ToLower ()) {return i}}
— wesm

나는 우리가 결코 알지 못할 것 같아요.
— Denny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.