C# WinForm中将子集求和结果回写至原有DataTable的实现咨询
实现方案
步骤1:调整数据读取与子集生成逻辑
原有逻辑仅存储了子集的数值拼接结果与求和值,需要调整为同时存储子集对应行的Sno编号,方便后续回写DataTable。默认你原表的Sno列为主键唯一列,若还未新增标签列先执行以下代码:
// 标签列已存在可跳过本段 if (!dm.Columns.Contains("标签")) { dm.Columns.Add("标签", typeof(string)); }
调整后的数据读取与子集生成代码如下:
// 同时读取每行的唯一Sno和待计算数值 var rowData = dm.AsEnumerable() .Select(r => new { Sno = r.Field<int>("Sno"), Value = double.Parse(r.Field<string>(dm.Columns[2])) }) .ToList(); double[] arrDouble = rowData.Select(x => x.Value).ToArray(); // 子集存储结构调整为:Item1=选中行的Sno集合,Item2=子集求和结果 List<Tuple<List<int>, double>> list = new List<Tuple<List<int>, double>>(); list.Add(new Tuple<List<int>, double>(new List<int> { rowData[0].Sno }, arrDouble[0])); for (int i = 1; i < arrDouble.Length; i++) { var newlist = new List<Tuple<List<int>, double>>(); list.ForEach(l => { var newSnoList = new List<int>(l.Item1) { rowData[i].Sno }; newlist.Add(new Tuple<List<int>, double>(newSnoList, l.Item2 + arrDouble[i])); }); list.Add(new Tuple<List<int>, double>(new List<int> { rowData[i].Sno }, arrDouble[i])); list.AddRange(newlist); }
步骤2:保留最优解筛选逻辑
原有筛选逻辑基本不变,仅需调整变量接收包含Sno集合的最优解:
double sumN = arrDouble.Sum(); double targetN = 你的目标求和值; // 替换为实际业务的目标数值 Tuple<List<int>, double> solution2; if (sumN > targetN) { solution2 = list.Where(l => l.Item2 >= targetN).OrderBy(o => o.Item2).First(); } else { solution2 = list.Where(l => l.Item2 >= sumN).OrderBy(o => o.Item2).Last(); } double lowest_weight = list.Min(c => c.Item2); Tuple<List<int>, double> solution1; if (targetN > lowest_weight) { solution1 = list.Where(l => l.Item2 <= targetN).OrderBy(o => o.Item2).Last(); } else { solution1 = list.Where(l => l.Item2 >= targetN).OrderBy(o => o.Item2).First(); } // 选出距离目标值最近的最终最优解 Tuple<List<int>, double> finalSolution = Math.Abs(solution2.Item2 - targetN) < Math.Abs(solution1.Item2 - targetN) ? solution2 : solution1;
步骤3:回写标签列到DataTable
拿到最优解包含的Sno集合后,直接匹配对应行写入标签即可:
// 清空历史标签 foreach (DataRow row in dm.Rows) { row["标签"] = DBNull.Value; } // 给最优子集包含的行写入对应Sno,可根据需求自定义标签格式 foreach (int sno in finalSolution.Item1) { DataRow matchRow = dm.AsEnumerable().First(r => r.Field<int>("Sno") == sno); matchRow["标签"] = sno.ToString(); }
注意事项
- 现有子集生成逻辑时间复杂度为O(2^n),仅适合行数不超过20的小数据量场景,行数过多会出现严重性能问题。
- 若你的Sno列名称和默认不一致,需替换代码中对应的列名为实际名称。
内容的提问来源于stack exchange,提问作者Muhammad Sajid
相关产品推荐
相关产品推荐

