集合中各元素任意组合的枚举方法
因在工作中遇到一个需要对某集合中各个元素的进行无序任意组合的要求.苦思多天,某天终于开窍,得到以下代码,特记录之. 不过代码中仍有需要优化的地方(当集合中元素个数超过8个以后,速度会几何级的变慢,主要出现在处理无序时需要进行字符串比较上).
运行环境: VS2010
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; namespace ConsoleApplication1 { [TestFixture] public class test { [Test] public void Test_layout() { //string[] strs = { "A", "B", "C", "D", "E", "F" }; string[] strs = { "209", "50", "460", "905", "715", "198" }; LayoutClass lay = new LayoutClass(); List<string> chs = new List<string>(strs); List<string> results = lay.Get_EnumList(chs); foreach (string s in results) Console.WriteLine(s); Console.WriteLine("--------------------------\r\nresults.Count=" + results.Count); } } public class LayoutClass { public LayoutClass() { } #region Get_EnumList() 主函數. 求傳入的各元素的所有無序全集合. /// <summary> /// 求傳入的各元素的所有無序全集合. /// 每個集合中包含所有元素, /// 各元素或單獨(以逗號分隔表示), /// 或組合(以加號連接表示). /// </summary> /// <param name="strs"></param> /// <returns></returns> public List<string> Get_EnumList(List<string> strs) { List<string> results = new List<string>(); for (int i = 0; i < strs.Count; i++) { SubEnumList(strs, results); ShiftList(strs); } return results; } #endregion #region ShiftList() List中的各元素向前移位.每次移一位 /// <summary> /// List中的各元素向左移位.每次移一位 /// </summary> /// <param name="strs"></param> void ShiftList(List<string> strs) { if (strs.Count <= 1) return; strs.Insert(0, strs[strs.Count - 1]); strs.RemoveAt(strs.Count - 1); } #endregion #region SubEnumList() 取得傳入的字串數組的單向無序子集合 /// <summary> /// 取得傳入的字串數組的單向無序子集合,該子集合必須包含所有元素. /// </summary> /// <param name="strs">各元素集合.如A,B,C,D</param> /// <param name="results">传址,用于承载所有子集合.如A,B,C+D | A,B+C+D | ... </param> void SubEnumList(List<string> strs, List<string> results) { if (strs.Count == 1) { results.Add(strs[0]); return; } for (int i = 0; i < strs.Count; i++) { string headstr = ArrayToString(strs.GetRange(0, i + 1), "", ","); List<string> subresult = new List<string>(); // 遞歸求子集合 SubEnumList(strs.GetRange(i + 1, strs.Count - i - 1), subresult); // 在求得的子集合中,將之加上字頭存入結果表中 foreach (string s in subresult) { string newstr = headstr + "," + s; if (!StrInArrayList(results, newstr)) results.Add(newstr); newstr = headstr + "+" + s; if (!StrInArrayList(results, newstr)) results.Add(newstr); } } } #endregion #region ArrayToString() 字符串List串成字符串輸出 /// <summary> /// 將字符串List串成字符串輸出 /// </summary> /// <param name="chs">字符串List</param> /// <param name="extra_str">不含在輸出字串中的元素,多個以逗號分隔.</param> /// <param name="spchar">輸出字串時的分隔符</param> /// <returns></returns> string ArrayToString(List<string> chs, string extra_str, string spchar) { StringBuilder sb = new StringBuilder(); string ls_str = string.Empty; string[] extrastrs = extra_str.Split(','); foreach (string s in chs) { if (extrastrs.Contains<string>(s)) continue; if (sb.Length == 0) sb.Append(s); else { sb.Append(spchar); sb.Append(s); } } return sb.ToString(); } #endregion #region StrInArrayList() 檢測字串在集合中是否已有類似的存在 /// <summary> /// 檢測字串在集合中是否已有類似的存在(無序).如"A,B,C+D" 與"D+C,B,A"定義為類似 /// </summary> /// <param name="chs"></param> /// <param name="s"></param> /// <returns></returns> bool StrInArrayList(List<string> chs, string s) { foreach (string substr in chs) { if (StringLike(substr, s, ',')) return true; } return false; } #endregion #region StringLike() 檢測兩個字串是否類似(無序).如"A,B,C+D" 與"D+C,B,A"定義為類似 /// <summary> /// 檢測兩個字串是否類似(無序).如"A,B,C+D" 與"D+C,B,A"定義為類似 /// </summary> /// <param name="chs"></param> /// <param name="s"></param> /// <param name="splitchar"></param> /// <returns></returns> bool StringLike(string chs, string s, char splitchar) { string[] as_str1 = chs.Split(splitchar); string[] as_str2 = s.Split(splitchar); if (as_str1.Length != as_str2.Length) return false; int likecount = 0; foreach (string substr in as_str1) { if (substr.Contains('+')) { bool findlike = false; foreach (string sub2 in as_str2) { if (!sub2.Contains("+")) continue; if (StringLikeOnlyCheckUnion(substr, sub2)) { findlike = true; break; } } if (findlike) likecount++; continue; } else { if (!as_str2.Contains<string>(substr)) return false; likecount++; } } return likecount == as_str2.Length; } #endregion #region StringLikeOnlyCheckUnion() 檢測包含有+號的字串, 其中的元素是否都在前一個字串中且以+號分隔 /// <summary> /// 檢測包含有+號的字串, 其中的元素是否都在前一個字串中且以+號分隔 /// </summary> /// <param name="chs"></param> /// <param name="s"></param> /// <returns></returns> bool StringLikeOnlyCheckUnion(string chs, string s) { string[] as_str1 = chs.Split(','); foreach (string substr in as_str1) { if (substr.Contains('+')) { if (StringLike(substr, s, '+')) { return true; } } } return false; } #endregion } }