【问题标题】:Increasing Loop Efficiency提高循环效率
【发布时间】:2015-10-08 17:02:46
【问题描述】:

背景

我有一个包含数字列表的表格。我检索此列表并将其放入数据表中。然后,我遍历表中的行并显示 1000 到 9999 之间不在表中的每个数字。

我的循环

static DataTable table = new DataTable();

foreach (DataRow row in table.Rows)
            {
                int id = Convert.ToInt32(row["stationid"]);

                for (int i = 1000; i < 9999 - table.Rows.Count; i = i++)
                {
                    if (i != id)
                    {

                                stationIdsTb.Text += Environment.NewLine;
                                stationIdsTb.Text += i.ToString();

                     }
                 }
             }

问题

但是这种方法确实有效。它非常慢。

有没有更高效、更快捷的方法来计算 1000 到 9999 之间不在数据表中的数字?

【问题讨论】:

  • 澄清一下,您的代码没有给出正确的结果,对吧?因为您描述的内容与您的代码不匹配。 (前几个回答的人建议使用更快的代码,但逻辑大体相同,因此仍然无法正常工作)。
  • @piojo,不,它确实给出了正确的结果,只是需要很长时间。也许我没有正确解释。我想显示不在数据表中且介于 1000 和 9999 之间的每个数字。
  • 有趣。你确定吗?该代码看起来确实会多次给出 1000 到 9999 之间的每个数字,而那些在数据库中的数字会更少,但仍然会给出。
  • @piojo,抱歉。你说的对。它确实会产生同一个列表的多个输出。
  • 很酷,那就多关注后面的答案——他们花时间注意到了差异。 :)

标签: c# loops if-statement foreach iteration


【解决方案1】:

您的循环并不慢。但是所有这些字符串连接都是。由于字符串是不可变的,因此您正在为每个连接创建一个新的 string 对象,这会不必要地复制内存并增加大量 GC 压力。

使用StringBuilder

var sb = new StringBuilder();

foreach (DataRow row in table.Rows)
{
    int id = Convert.ToInt32(row["stationid"]);
    var max = Math.Max(9999, table.Rows.Count);

    for (int i = 1000; i < max; ++i)
    {
        if (i != id)
            sb.AppendLine().Append(i); // Or just sb.AppendLine(i); maybe?
    }
}

stationIdsTb.Text = sb.ToString();

顺便说一句,写i = i++ 真的是错误的,因为它基本上是无操作的。


更新:

显示 1000 到 9999 之间不在表格中的每个数字。

这并不是你的代码正在做的事情,但如果它真的是你想要的,这里有一个更简单的方法:

var stationIds = new HashSet<int>(
    table.Rows.Cast<DataRow>().Select(row => Convert.ToInt32(row["stationid"]))
);

var sb = new StringBuilder();
for (var i = 1000; i <= 9999; ++i)
{
    if (!stationIds.Contains(i))
        sb.AppendLine(i);
}

stationIdsTb.Text = sb.ToString();

【讨论】:

  • 9 秒对我来说太快了 :-)
  • @Zohar hehe :-) 但你应该从Append 中删除ToString,我也发现了i = i++ 的东西;-)
  • @LucasTrzesniewski,虽然这绝对是一种更聪明、更有效的方法。但所需的时间似乎并没有大幅减少。数据表包含 742 行,因此循环必须执行 742 * 9999 = 7419258 次迭代。目前,即使你改进了日常工作,在我的 i7 笔记本电脑上也需要大约 5 分钟。
  • @KingCundy 我不想过多地改变你的逻辑,我的更新能解决你的问题并满足你的需求吗?
  • @LucasTrzesniewski 该答案更新完全是我的答案:)
【解决方案2】:

不要使用stationIdsTb.Text += ...,而是使用StringBuilder

StringBuilder sb = new StringBuilder();

foreach (DataRow row in table.Rows)
{
    int id = Convert.ToInt32(row["stationid"]);

    for (int i = 1000; i < 9999 - table.Rows.Count; i++)
    {
        if (i != id)
        {
         sb.AppendLine().Append(i);
         }
    }
}

stationIdsTb.Text = sb.ToString();

【讨论】:

    【解决方案3】:

    许多问题 1)如果你想在前端使用 linq 2)不要使用数据表。此外,无论需要什么列,只选择那些使数据表大小更小的列。

    【讨论】:

      【解决方案4】:

      这就是我的做法.. 除非我错过了什么,否则不理解当前的方法 - 假设 1,000 不在表中 - 您最终会检查 1,000 并将其添加到您的结果中表中的每一行。我假设您想要一个不同的缺失数字列表。

      // get all the numbers in the list
      HashSet<int> numbersInTable = new HashSet<int>(dataTable.AsEnumerable().Select(a => (int)a["StationId"]));
      
      // between 1000-9999, find numbers not in the set
      List<int> missingNumbers = Enumerable.Range(1000, 9000).Except(numbersInTable).ToList();
      
      // convert to a string
      string result = String.Join(Environment.NewLine, missingNumbers.ConvertAll<string>(a => a.ToString()));
      

      【讨论】:

        【解决方案5】:

        如果您愿意显示 1000 到 9999 之间不在表格中的数字,那么您做错了。您可以将 "stationid" 列设置为主键并在 for 循环中查看主键是否包含当前数字。如果我弄错了,请纠正我,但这应该是正确的解决方案:

        table.PrimaryKey = new DataColumn[] { table.Columns["stationid"] };
        
        StringBuilder sb = new StringBuilder();
        for (int i = 1000; i <= 9999; i++)
        {
            if (!table.Rows.Contains(i))
                sb.AppendLine(i);
        }
        
        stationIdsTb.Text = sb.ToString();
        

        设置主键后也可以这样做:

        stationIdsTb.Text = String.Join(Environment.NewLine, Enumerable.Range(1000, 9000).Where(number => !table.Rows.Contains(number)));
        

        【讨论】:

        • 我认为应该是sb.AppendLine(i);
        猜你喜欢
        • 2019-11-06
        • 2018-04-18
        • 1970-01-01
        • 1970-01-01
        • 2019-12-05
        • 2019-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多