你是不是有遇過這種邏輯需求: if (x == “A” || x == “B” || x == “C” || x == “D” ….),x滿足其中任一即可。當可能選項很多時,程式碼就會又臭又長,此時不免有個念頭,如果可以像SQL寫成WHERE X IN ('A', 'B', 'C', 'D' ...)多好?

我慣用的做法是借用.NET 2.0的System.Collections.Generic的List<string>,其中有個Contains()方法可產生類似效果:
【2009-06-06更新】感謝大估補充,其實Array.IndexOf(Array, string)就可以提供相同的比對功能,可省去動用List<string>的步驟,寫法上更簡潔。我又再次抛磚引玉,賺到了。
【2009-06-07更新】賺翻了,丟了顆小石頭,結果掉出鑽石來!! chicken大給了個絕佳的點子,bool WhereIn(x, "A", "B", "C"),詳見留言區。(註: 再次證明本站的留言比貼文精彩,建議可以長期訂閱哦!)

using System;
using System.Collections.Generic;
 
public class CSharpLab
{
    private static string getTestResult(
                    List<string> lst, string target)
    {
        bool test = lst.Contains(target);
        string result = 
            string.Format("[{0}] {1} in ('{2}')!",
            target, test ? "is" : "is not",
            string.Join("','", lst.ToArray()));
        return result;
    }
 
    public static void Test()
    {
        List<string> lst = 
            new List<string>("A,B,C,D,E,F".Split(','));
        string x = "X";
        Console.WriteLine(getTestResult(lst, x));
        lst.Add("X");        
        Console.WriteLine(getTestResult(lst, x));
    }
}

執行結果為: (程式碼可以複製到Mini C# Lab中直接執行)

[X] is not in ('A','B','C','D','E','F')!
[X] is in ('A','B','C','D','E','F','X')!

很簡單吧! 整篇的關鍵只在lst.Contains()那一列,其餘的部分都是為了舖陳這個梗而灑的花瓣(XD)...

順道一提,上面的程式碼裡有幾個我常用的小技巧:

  • string.Split(char)可以將一個逗號分隔的字串轉成string[]
  • new List<string>(string[])可以直接將字串陣列轉成List<string>
  • List<string>.ToArray()可以匯出string[]
  • string.Join(string, string[])可以將字串陣列用指定的分隔文字再組成一個字串。用"','"間隔,前後加上"('"及"')",就搞出('A','B’,…,’X’)囉! (不過我偷懶沒避開無元素的情境,會變成(''))

類似的情境,如果大家有不一樣的解法,歡迎提出來交流。


Comments

# by 大估

黑暗大您好: 以下是小弟的寫法(省略 組出結果的字串) dim stra as string()="A,B,C,D,E,F".Split(",") if array.indexof(stra,"A")>-1 then Console.WriteLine("yes") else Console.WriteLine("no") end if 1.先將傳入的字串轉為字串陣列。 2.使用array.indexof 來判斷是否存在。 3.之前在網路上,有善心人士有作過測試, list<string> vs string() list<string>作援尋,會比在string()中作援尋快,所以黑暗大寫的語法,如果在資料量時大,推薦使用~ 以上

# by Jeffrey

to 大估,這方法很棒,比我的做法更簡便,我學起來了。(筆記...)

# by 大估

謝謝黑暗大的肯定~~ 對了,大估自己的留言錯字訂正: list<string>作【搜尋】,會比在string()中作【搜尋】快,所以黑暗大寫的語法,如果在資料量時大,推薦使用~

# by 小熊子

我會用 [C#] Predicate Delegate 來做 http://www.michadel.net/post/20080711_surprise_on_Predicate_Delegate.aspx Predicate Delegate 也支援 Array.Find()

# by chicken

我的想法很簡單,這種問題只有兩個關鍵: 1. interface / syntax 設計的夠不夠好用? 2. 效率夠不夠好? 既然只是回 comment, 就簡單的寫 :D interface 的部份,我個人篇愛一行能寫完,簡單明瞭的作法. 我會另外弄個 Method, 像這樣: public static bool WhereIn<T>(T source, params T[] items) {...} 用的時後很簡單: if (WhereIn<string>(x, "A", "B", "C", "D")) { //... } else { //... } 再來才是效能。只有兩三筆的話,都大同小異吧,越簡單的演算法應該越快。 如果真的要考量到巨量的資料,還是得搬出 O(xxx) 出來看... 如果只用一次就扔掉,Array 是最快的 ( 查詢: O(n) )... 如果有任何機會省掉建立 data structure 的話 (比如用 cache),那麼 HashSet 應該是最快的 ( 建立: O(n), 查詢: O(1) ) public static bool WhereIn<T>(T source, params T[] items) { HashSet<T> set = new HashSet<T>(items); return set.Contains(source); }

# by Jeffrey

to chicken, 有見地,這點子妙極了,大推!!

# by chicken

補個變態一點的版本... 用 C# extension method 做的... 不用傷腦筋在那個 class 底下掛 method .. 不過那個 generic 處理的不大漂亮 @@,補上 <string> 感覺很多餘,不過不補的話就得用 object, 相較之下加個 type parameter 好像好一點... 先貼一下: // sample code: string text = "A"; if (text.WhereIn<string>("A", "B", "C") == true) { Console.WriteLine("Match!!"); } // extension class: public static class WhereInExtension { public static bool WhereIn<T>(this T source, params T[] items) { HashSet<T> set = new HashSet<T>(items); return set.Contains((T)source); } }

# by ningin

謝謝分享 這真的超好用 縮減很多程式碼 非常感謝

Post a comment