【问题标题】:Efficient Method for Creating CSV String from Lists/SortedLists C#?从列表/排序列表 C# 创建 CSV 字符串的有效方法?
【发布时间】:2011-05-24 11:00:35
【问题描述】:

我有一个实现异步 SOAP 的应用程序。每 50-100 毫秒,我将收到转换为 SortedList<double,double> 对象的数据。我还有一个预定义的IList<double>,其中包含SortedList 中的所有可能键。

我需要遍历IList 并检查SortedList 是否包含该密钥。如果是,我将该值写入 csv 字符串;如果没有,我将 0.0 写入 csv 字符串。

注意: IList 有 400 个键。 SortedList 一般会比 400 小很多,最多 100 左右。

        string MyText = timestamp.ToString("HH:mm:ss");
        for (int i = 0; i < AllKeys.Count; i++)
        {
            double info;
            if (MySortedList.TryGetValue(AllKeys[i], out info))
            {
                MyText += "," + info;
            }
            else
            {
                MyText += ",0.0";
            }
        }
        MyText += "\n";

        File.AppendAllText(filePath, MyText);

我目前正在使用上述代码创建 csv 字符串,然后再将其写入我的文件。但是,我发现这段代码落后于我的应用程序。

我需要帮助提高效率,以便存储传入数据的时间低于 50 毫秒。一些额外的事情:

  • 我不必写入 csv 文件,我只需要快速存储数据。 (我可以稍后从序列化文件转换为我的 csv 文件)
  • 我曾考虑过使用 LINQ,但我对查询不熟悉,不知道它的效率会提高多少

编辑:我已经通过使用 Conrad 提出的制作 StreamWriter 对象的建议解决了我的性能问题。我只是创建了一个静态 StreamWriter 对象,并在通信终止时关闭 StreamWriter 之前将我的所有文本写入它。

【问题讨论】:

  • 对于初学者,请尝试使用 StringBuilder。这种事情通常比原生连接快得多(或者我听说过)。还有,你不是先说IList有SortedList的所有可能键,然后你说你需要检查它是否有吗?我错过了什么吗?
  • 我有一个 IList,它有 400 个双精度值,它们是 SortedList 中所有可能的键。我收到的 SortedList 数据具有与其中一些键(不是全部)关联的值。例如,IList 有 (1,2,3,4),而 sortedlist 有 ([1,6.6], [3,7.9]),我的 csv 字符串将是“6.6, 0.0, 7.9, 0.0”跨度>

标签: c# file csv io sortedlist


【解决方案1】:

我同意 Conrad 的回答 - 但提高性能的另一个想法是进行反向查找,即从 SortedList 中获取每个元素并在其他列表中进行查找(当然,我建议使用字典而不是列表更快查找)。

【讨论】:

  • 你能用一些代码澄清一下吗?如果我有 (1,2,3,4) 的列表和 ([1,6.6], [3,7.9]) 的排序列表,我将如何使用反向查找来获取字符串“6.6, 0.0, 7.9, 0.0"?
  • 糟糕——完全错过了 0.0 部分!不,我认为反向查找在这里没有帮助。
【解决方案2】:

我确定我还没有提出最有效的算法,但至少这里是一个起点。如果不出意外,您会注意到StringBuilder 的使用,而不是连接字符串。仅此一项就可能为您带来一些性能优势。

此算法假定 SortedList 键和“数据”列表都以相同的方式排序(从低到高)。

var textBuilder = new StringBuilder(timestamp.ToString("HH:mm:ss"));

var index = 0;
foreach(double key in data.Keys)
{
    while(Allkeys[index] < key)
    {
        textBuilder.Append(",0.0");
        index++;
    }

    textBuilder.Append(",").Append(data[key]);
    index++;
}
MyText = textBuilder.Append(@"\n").ToString();

仅查看以上内容,我确定存在错误,但如果不花更多时间和/或测试,我不确定是什么或在哪里。

一种可能的 LINQ 解决方案更具声明性:

var textBuilder = new StringBuilder(timestamp.ToString("HH:mm:ss"));

var values = Allkeys.Select(
    key => data.ContainsKey(key) ? data[key].ToString() : "0.0")
    .ToArray();

var data = String.Join(",", values);
var MyText = textBuilder.Append(data).Append(@"\n").ToString();

更多可以使用 Aggregate 扩展方法包含在 LINQ 表达式中,但您必须在累加器中使用字符串连接,所以我没有在这里展示。

【讨论】:

  • 谢谢,我刚试过这个,速度提高了不少。我也什么时候做了一些搜索,发现了这个性能测试图。 dotnetperls.com/stringbuilder-performance
  • 第一个代码的bug是SortedList中的最后一个Key并不总是IList中的最后一个Key。所以 (1,2,3,4,5) 的 IList 和 ([1,6.6], [3,7.8]) 的 SortedList 只会产生 "6.6,0.0,7.8"
【解决方案3】:

这里有一些想法。

1) 使用StreamWriter 代替文件进行写入。这将比写入内存然后写入文件的两个步骤更快。

2) 如果可能的话,将工作并行化。例如,如果您可以一个线程处理消息,另一个线程编写消息。

3) 我不认为 LINQ 的目的是提高性能,而是让数据操作更容易

【讨论】:

  • 我喜欢并行化的想法,有没有可能找个例子让我开始?我不确定如何编写好的线程管理程序
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-28
  • 2011-04-20
  • 2020-04-21
  • 1970-01-01
  • 2022-11-16
相关资源
最近更新 更多