以指定分隔符串聯字串
阿新 • • 發佈:2018-11-05
對於String.Join(String, String[])這個方法,相信大家都有所瞭解。唯一不足的就是這個方法只能用於字串陣列,適用場景比較少。我所遇到的場景中,更多的是對List<T>中的某屬性進行串聯。尚未發現已實現該功能的方法,於是自己實現了該功能。
實現的方式是對IEnumerable<T>進行擴充套件。
/// <summary> /// 將數組合併成字串,Action<<typeparamref name="T"/>,TextWriter> /// </summary> /// <typeparam name="T"></typeparam> /// <param name="enumerable"></param> /// <param name="separator"></param> /// <param name="action"></param> /// <param name="output"></param> public static void Join<T>(this IEnumerable<T> enumerable,String separator,Action<T,TextWriter> action,TextWriter output) { Func<TextWriter, String,Boolean> writeSp = (x, y) => { x.Write(y); return true; }; IEnumerator<T> en = enumerable.GetEnumerator(); if(en.MoveNext()) { do { action(en.Current,output); } while(en.MoveNext() && writeSp(output, separator)); } } /// <summary> /// 將數組合併成字串,Action<<typeparamref name="T"/>> /// </summary> /// <typeparam name="T"></typeparam> /// <param name="enumerable"></param> /// <param name="separator"></param> /// <param name="action"></param> /// <param name="output"></param> public static void Join<T>(this IEnumerable<T> enumerable,String separator,Action<T> action,TextWriter output) { Func<TextWriter, String,Boolean> writeSp = (x, y) => { x.Write(y); return true; }; IEnumerator<T> en = enumerable.GetEnumerator(); if(en.MoveNext()) { do { action(en.Current); } while(en.MoveNext() && writeSp(output, separator)); } }
下面通過實現“DataTable轉CSV”來對這兩個方法和巢狀For迴圈進行對比。
在這個Demo裡,DataTable有3列100行資料。對3種實現方式分別進行10000、100000和1000000迴圈。
Demo:
[TestMethod] public void TestMethod5() { DataTable dt = new DataTable("1234"); dt.Columns.Add("A"); dt.Columns.Add("B"); dt.Columns.Add("C"); for(int i = 0; i < 100; i++) { dt.Rows.Add("A" + i, "B" + i, "C" + i); } StringBuilder sb;//= new StringBuilder(); StringWriter sw;// = new StringWriter(sb); String rowSeparator = "\n"; String columnSeparator = ","; //Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffffff")); DateTime time1 = DateTime.Now; Int32 count = 1000000; for(int c = 0; c < count; c++) { sb = new StringBuilder(); sw = new StringWriter(sb); #region Action<T,TextWriter> // var columns = dt.Columns.OfType<DataColumn>(); //// 寫標題 //columns.Join(columnSeparator, (x) => x.ColumnName, sw); //sw.Write(rowSeparator); //// 寫資料 //dt.Select().Join(rowSeparator, (x, x1) => columns.Join(columnSeparator, (y, y1) => { y1.Write('"'); y1.Write(x[y]); y1.Write('"'); }, x1), sw); #endregion #region Action<T> // var columns = dt.Columns.OfType<DataColumn>(); //columns.Join(columnSeparator, (x) => sw.Write(x.ColumnName), sw); //sw.Write(rowSeparator); //dt.Select().Join(rowSeparator, (x) => columns.Join(columnSeparator, (y) => { sw.Write('"'); sw.Write(x[y]); sw.Write('"'); }, sw), sw); #endregion #region 巢狀for Func<TextWriter, String, Boolean> func = (x, y) => { x.Write(y); return true; }; sb = new StringBuilder(); for(int i = 0; i < dt.Columns.Count && func(sw, columnSeparator); i++) { sw.Write(dt.Columns[i].ColumnName); } sw.Write(rowSeparator); for(int i = 0; i < dt.Rows.Count && func(sw, rowSeparator); i++) { for(int j = 0; j < dt.Columns.Count && func(sw, columnSeparator); j++) { sw.Write('"'); sw.Write(dt.Rows[i][j]); sw.Write('"'); } } #endregion sw.Flush(); sw.Close(); //Console.WriteLine(sb.ToString()); } //Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffffff")); DateTime time2 = DateTime.Now; Console.WriteLine($"{time1.ToString("yyyy-MM-dd HH:mm:ss:ffffff")}\t{time2.ToString("yyyy-MM-dd HH:mm:ss:ffffff")}\t{time2.Ticks - time1.Ticks}"); }
測試結果:
類別 | 迴圈次數 | 開始時間 | 結束時間 | Ticks差 |
---|---|---|---|---|
Action<T,TextWriter> | 10000 | 2018-11-05 22:13:58:619431 | 2018-11-05 22:14:01:708661 | 30862597 |
Action<T> | 10000 | 2018-11-05 22:30:01:316414 | 2018-11-05 22:30:04:540565 | 32241503 |
巢狀for | 10000 | 2018-11-05 22:48:20:351136 | 2018-11-05 22:48:23:832171 | 34810345 |
Action<T,TextWriter> | 100000 | 2018-11-05 22:17:45:756623 | 2018-11-05 22:18:14:361243 | 286046197 |
Action<T> | 100000 | 2018-11-05 22:30:38:917299 | 2018-11-05 22:31:08:680268 | 297629687 |
巢狀for | 100000 | 2018-11-05 22:50:11:315021 | 2018-11-05 22:50:45:257604 | 339425834 |
Action<T,TextWriter> | 1000000 | 2018-11-05 22:19:02:489665 | 2018-11-05 22:24:06:528472 | 3040388071 |
Action<T> | 1000000 | 2018-11-05 22:32:09:871650 | 2018-11-05 22:37:05:125522 | 2952538718 |
巢狀for | 1000000 | 2018-11-05 22:51:18:319466 | 2018-11-05 22:56:46:534431 | 3282149643 |
從結果中可以看出,效能差距並不大。當然,由於巢狀For迴圈裡使用索引來尋值,所以可能存在誤差。
如果有錯誤或者更好的方法,歡迎指正。
題外話,方法命名為Join,可能與Linq的Join存在歧義,建議使用時換成其他名稱。