重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
对于String.Join(String, String[])这个方法,相信大家都有所了解。唯一不足的就是这个方法只能用于字符串数组,适用场景比较少。我所遇到的场景中,更多的是对List
实现的方式是对IEnumerable
///
/// 将数组合并成字符串,Action< ,TextWriter>
///
///
///
///
///
///
public static void Join(this IEnumerable enumerable,String separator,Action action,TextWriter output)
{
Func writeSp = (x, y) => { x.Write(y); return true; };
IEnumerator en = enumerable.GetEnumerator();
if(en.MoveNext())
{
do
{
action(en.Current,output);
} while(en.MoveNext() && writeSp(output, separator));
}
}
///
/// 将数组合并成字符串,Action< >
///
///
///
///
///
///
public static void Join(this IEnumerable enumerable,String separator,Action action,TextWriter output)
{
Func writeSp = (x, y) => { x.Write(y); return true; };
IEnumerator 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
// var columns = dt.Columns.OfType();
//// 写标题
//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
// var columns = dt.Columns.OfType();
//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 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 | 10000 | 2018-11-05 22:13:58:619431 | 2018-11-05 22:14:01:708661 | 30862597 |
Action | 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 | 100000 | 2018-11-05 22:17:45:756623 | 2018-11-05 22:18:14:361243 | 286046197 |
Action | 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 | 1000000 | 2018-11-05 22:19:02:489665 | 2018-11-05 22:24:06:528472 | 3040388071 |
Action | 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存在歧义,建议使用时换成其他名称。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。