提高环路效率

本文关键字:效率 高环路 | 更新日期: 2023-09-27 18:03:22

背景

我有一张表,里面有一张号码表。我检索这个列表并将其放入数据表中。然后,我遍历表中的行,并显示表中没有的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之间的数字

提高环路效率

您的循环并不慢。但所有这些字符串串联都是。由于字符串是不可变的,因此每次串联都会创建一个新的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();

不要使用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();

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

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)));

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

以下是我的操作方法……除非我遗漏了什么,否则不理解当前的方法——假设1000不在表中——你最终会检查1000,并将其添加到表中每一行的结果中。我想你想要一份缺失数字的清晰清单。

// 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()));