【问题标题】:Optimizing text conversion to list of integers优化文本转换为整数列表
【发布时间】:2013-01-13 09:00:20
【问题描述】:

我正在编写一个接受用户输入的 UI 应用程序 -

他将最多 50,000 个条目粘贴到 Textbox,我需要将其转换为 List<Uint32>(不同)

在这个过程中,我在“文本框”中显示了Distict列表(输出)。

我正在拆分文本并将其转换为 Uint32 的 Distinct 列表 然后我将列表转换为数组。

private List<UInt32> ConvertTextToList(string TextBoxText)
{
string[] TextBoxSplitted = TextBoxText.Split(new string[] { Environment.NewLine},StringSplitOptions.RemoveEmptyEntries); //Fast
            var TextBoxSplittedAsList = TextBoxSplitted.ToList<string>(); //Fast
            List<UInt32> lp = TextBoxSplittedAsList.ConvertAll(new Converter<string, UInt32>(element => Convert.ToUInt32(element))); //Fast
            List<UInt32> uintList = lp.Distinct<UInt32>().ToList<UInt32>(); //Fast
            UInt32[] uintListArray = uintList.ToArray(); //Fast

            //Slow part (measured 15 sec on core2duo 2.53GHz)
            StringBuilder builder = new StringBuilder();
            Array.ForEach(uintListArray, x => builder.Append(x));                
            //Done slow part

            SomeTextBox.text = builder.ToString();

            return uintList;
}

首先我尝试使用 - ListOfHeliostatsText.Text = string.Join(",", uintListArray);

哪个更慢(比使用 StringBuilder 慢约 25%)

感觉我的函数设计错了,两次多次转换。

有没有办法提高这个功能的性能?

编辑: 我的错, 慢的部分是 ListOfHeliostatsText.Text = builder.ToString();

我会继续阅读答案。

【问题讨论】:

  • 与您的问题没有直接关系...您不需要 both uintListuintListArray。由于您没有添加/删除任何元素,因此只需使用数组。
  • 您确定用户输入完全正确吗?
  • 我试过你说的代码很慢,运行大约10毫秒。在我的电脑上,它具有相同的处理器。如果我使数组包含 8000 万个项目而不是 50000 个,我会接近你所说的。你是如何测量时间的?
  • 我的错,慢的部分在SomeTextBox.text = builder.ToString()@BrankoDimitrijevic 在他的回答中提到。

标签: c# string .net-4.0


【解决方案1】:

您测量错误。慢的部分是不是

StringBuilder builder = new StringBuilder();
Array.ForEach(uintListArray, x => builder.Append(x)); 

缓慢的部分是:

SomeTextBox.Text = builder.ToString();

问题是您在文本框中输入了一大行。如果您将每个字符串放在自己的行中......

Array.ForEach(uintListArray, x => builder.AppendLine(x.ToString()));

...您将观察到大约 50 倍的加速。

【讨论】:

  • 我接受这个答案。虽然它没有解决我的问题,但它指出了我的测量错误。我将使用 this - 加速 winforms 文本框。谢谢大家的回答。
  • @Ofiris 所以拆分成多行不是一个解决方案……那么在文本框中存储这么大一行的目的是什么?用户应该如何理解它?我认为您正在尝试解决一个原本不应该存在的“问题”(通过更好的 UI 设计)...
  • 你是对的,这可能是一个糟糕的 UI 设计,关键是用户从文件中粘贴/加载输入,我必须显示它,通常它会是小的输入,但我没有控制输入​​的大小。
  • @Ofiris 输入不是问题,性能方面。您是否可以控制 输出 的格式?您可以使其格式与输入相同(即用新行分隔单个值)吗?
  • 我尝试将文本处理成uint数组,我可以以我选择的任何格式显示文本,但我想美化它,例如1 2,3;4,1,1应该是--> @987654327 @
【解决方案2】:

你可以试试这个吗:

private List<UInt32> ConvertTextToList(string TextBoxText)
{
   ....
    var TextBoxSplittedAsList = TextBoxSplitted.ToList<string>(); //Fast

    TextBoxSplittedAsList.Select(int.Parse).ToList();
    TextBoxSplittedAsList.Distinct().ToList(); // to get the distinct values

【讨论】:

    【解决方案3】:

    由于可能有这么多条目,我认为使用字符串拆分操作将中间值放入中间数组不会有帮助。这是很多开销。如果速度和效率是您的目标,您应该通过在读取项目时有效地阅读生成项目的字符串来对其进行标记。这样,您将不需要也不需要保存所有这些值的中间数组。

    如果您想获取所有不同的值,您可以将所有内容放入HashSet&lt;T&gt;。然而,我将在这里展示的示例将使用一些 LINQ 和 Distinct() 方法(它有自己的开销)。

    // a naive tokenizing iterator
    IEnumerable<string> Tokenize(string str, string separator)
    {
        var current = 0;
        while (current < str.Length)
        {
            // we're effectively scanning through the string
            var next = str.IndexOf(separator, current);
            if (next == -1)
            {
                next = str.Length;
            }
            var token = str.Substring(current, next - current);
            yield return token;
            current = next + 1;
        }
    }
    
    List<uint> ConvertTextToList(string text)
    {
        return Tokenize(text, ",")
            .Select(token => Convert.ToUInt32(token))
            .Distinct()
            .ToList();
    }
    

    听从我的建议,不要让该方法做任何事情,而不仅仅是生成该列表。您可以在该函数之外填充该文本框,它不属于那里。

    【讨论】:

    • 如果这个实现不够快,把它写成循环,不要使用LINQ。
    猜你喜欢
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 2016-02-04
    相关资源
    最近更新 更多