केस-असंवेदनशील सूची खोज


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% तेज है। हो सकता है कि कोई और इसकी पुष्टि / खंडन कर सकता है।
1

8
.NET 2.0 के अनुसार, यह अब आसानी से हो गया है - नीचे दिए गए शैक्सबी के उत्तर को देखें।
जो

3
Contains विधि shaxby का संदर्भ है (जिसमें एक अधिभार है जो IEqualityComparer लेता है) LINQ का हिस्सा है, इसलिए यह .NET 2.0 के बाद से निश्चित रूप से उपलब्ध नहीं है। बस थोड़ी देर के लिए StringComparer वर्ग के आसपास रहा है। सूची <T> के पास वह तरीका नहीं है, न ही ArrayList या StringCollection (वह चीजें जिन्हें वह आसानी से अपनी 'सूची' के रूप में संदर्भित कर सकता था)।
एडम

खैर, चूंकि मुझे वास्तव में सूचकांक की आवश्यकता थी , यह निश्चित रूप से मेरे लिए सबसे अच्छा जवाब था।
Nyerguds 12

1
पहला समाधान List<>.Exists(Predicate<>)उदाहरण विधि का उपयोग करना चाहिए । यह भी ध्यान दें कि यदि सूची में nullप्रविष्टियाँ हैं, तो यह उड़ा सकता है। उस स्थिति में यह कहना अधिक सुरक्षित keyword.Equals(x, StringComparison.OrdinalIgnoreCase)है x.Equals(keyword, StringComparison.OrdinalIgnoreCase)(यदि आप गारंटी दे सकते हैं कि यह keywordशून्य नहीं है)।
जेपी स्टिग नीलसन 12

360

मुझे लगता है कि यह एक पुरानी पोस्ट है, लेकिन अगर कोई और देख रहा है, तो आप इस तरह से मामले को असंवेदनशील स्ट्रिंग समानता प्रदान करके उपयोग कर सकते हैं Contains:

using System.Linq;

// ...

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

यह उपलब्ध है .net 2.0 msdn के अनुसार ।


21
निश्चित रूप से सबसे अच्छा जवाब यहाँ। :)
जो

22
Enumerable <T> .Contains (जो आप संदर्भित कर रहे हैं) .NET 2.0 के बाद से आसपास नहीं है। कोई सूची <T> नहीं है। आपके द्वारा उपयोग किया जा रहा अधिभार है।
एडम

@AdamSills सही। सूची <T> में ऐसी कोई विधि नहीं है। और अगर यह एक आलसी संग्रह है, तो यह अन्य Enumerable <T> विधियों के रूप में इसे कई बार दोहरा सकता है। Imho, इस विधि का उपयोग ऐसे मामलों के लिए नहीं किया जाना चाहिए, क्योंकि यह उस मामले के लिए इतना तार्किक नहीं है।
सेर्गेई लिट्विनोव

40
मैं इस अधिभार को पहले तो नहीं देख रहा था, लेकिन आपको System.Linq का उपयोग करने की आवश्यकता है।
माइकल

1
StringComparerवर्ग 2.0 के बाद से आसपास किया गया है, लेकिन इसमें शामिल की है कि अधिभार 3.5 में पेश किया गया था। msdn.microsoft.com/en-us/library/bb339118(v=vs.110).aspx
डेनिस स्किडमोर

18

ऊपर दिए गए एडम सील्स के जवाब के आधार पर - इसमें कॉन्टेन्स के लिए एक अच्छा साफ एक्सटेंशन तरीका है ... :)

///----------------------------------------------------------------------
/// <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 का उपयोग कर" जोड़ते हैं, अन्यथा आप उस ओवरलोड को नहीं देखेंगे।
जूलियन मेलविले

1

लांस लार्सन जवाब के आधार पर - यहाँ स्ट्रिंग के बजाय अनुशंसित स्ट्रिंग के साथ एक विस्तार विधि दी गई है

यह अत्यधिक अनुशंसा की जाती है कि आप String.Compare के अधिभार का उपयोग करें जो StringComparison पैरामीटर लेता है। न केवल ये ओवरलोड आपको आपके द्वारा बताए गए सटीक तुलना व्यवहार को परिभाषित करने की अनुमति देते हैं, बल्कि उनका उपयोग करके आपके कोड को अन्य डेवलपर्स के लिए अधिक पठनीय बनाया जा सकता है। [ जोश फ्री @ बीसीएल टीम ब्लॉग ]

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

यदि इंडेक्सऑफ का परिणाम बड़ा या बराबर 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; }
}

यदि आप किसी ऐसी पुस्तक को निकालना चाहते हैं जिसमें पाठ संपत्ति में कुछ कीवर्ड हैं, तो आप कीवर्ड की एक सूची बना सकते हैं और इसे पुस्तकों की सूची से हटा सकते हैं:

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
दूसरी सूची क्यों तैयार करें? यह बहुत कुशल नहीं है। के लिए (var i = 0; मैं <itemsList.Count; i ++) {if (item.ToLower () == searchItem.ToLower ()) {वापसी i}}
wesm

मुझे लगता है कि हम कभी नहीं जान पाएंगे।
डेनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.