提高环路效率
Increasing Loop Efficiency
背景
我有一个 table,其中包含一个数字列表。我检索此列表并将其放入数据table。然后我遍历 table 中的行并显示 1000 到 9999 之间不在 table.
中的每个数字
我的循环
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 之间的数字table?
你的循环并不慢。但是所有这些字符串连接都是。由于字符串是不可变的,因此每次连接都会创建一个新的 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++
是 真的 错误,因为它基本上是空操作。
更新:
display every number between 1000 and 9999 that isn't in the table.
你的代码不完全是这样做的,但如果它真的是你想要的,这里有一个更简单的方法:
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();
很多问题
1)如果你想在前端使用linq
2)不要使用数据表。此外,无论需要什么列,只有 select 那些,这样数据表的大小就会变小。
我会这样做..除非我遗漏了什么,否则不理解当前的方法 - 假设 1,000 不在 table - 你最终会检查 1,000 和将它添加到 table 中每一行的结果中。我假设您想要一个不同的缺失数字列表。
// 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()));
如果您愿意显示 table 中没有的 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)));
背景
我有一个 table,其中包含一个数字列表。我检索此列表并将其放入数据table。然后我遍历 table 中的行并显示 1000 到 9999 之间不在 table.
中的每个数字我的循环
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 之间的数字table?
你的循环并不慢。但是所有这些字符串连接都是。由于字符串是不可变的,因此每次连接都会创建一个新的 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++
是 真的 错误,因为它基本上是空操作。
更新:
display every number between 1000 and 9999 that isn't in the table.
你的代码不完全是这样做的,但如果它真的是你想要的,这里有一个更简单的方法:
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();
很多问题 1)如果你想在前端使用linq 2)不要使用数据表。此外,无论需要什么列,只有 select 那些,这样数据表的大小就会变小。
我会这样做..除非我遗漏了什么,否则不理解当前的方法 - 假设 1,000 不在 table - 你最终会检查 1,000 和将它添加到 table 中每一行的结果中。我假设您想要一个不同的缺失数字列表。
// 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()));
如果您愿意显示 table 中没有的 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)));