以指定分隔符串联字符串

发布时间:2020-08-01 13:29:49 作者:twoxzi
来源:网络 阅读:392

对于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存在歧义,建议使用时换成其他名称。

推荐阅读:
  1. python中如何指定多个分隔符
  2. SQL中怎么根据指定分隔符分解字符串

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c 字符串串 符串

上一篇:oracle 存储过程两次遍历游标

下一篇:oracle无密码登录

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》