如何从两个数组提取唯一字符串?及SQL获取缺勤学生姓名问题
问题解答:提取唯一字符串与缺勤学生查询
1. 如何通过比较两个数组来提取唯一的字符串值?
提取两个数组中独有的字符串,最简洁高效的方式是借助LINQ工具,也可以手动遍历实现,下面给你两种实用方案:
方案一:使用LINQ(推荐)
这种方式代码简洁且性能稳定,需要先引用System.Linq命名空间:
using System.Linq; // 示例数组 string[] array1 = {"apple", "banana", "cherry", "date"}; string[] array2 = {"banana", "date", "fig", "grape"}; // 获取array1中独有的字符串 string[] uniqueToFirst = array1.Except(array2).ToArray(); // 获取array2中独有的字符串 string[] uniqueToSecond = array2.Except(array1).ToArray(); // 获取两个数组中所有非交集的唯一字符串 string[] allUnique = array1.Union(array2).Except(array1.Intersect(array2)).ToArray();
如果需要忽略大小写匹配,可以添加字符串比较器:
string[] uniqueToFirstIgnoreCase = array1.Except(array2, StringComparer.OrdinalIgnoreCase).ToArray();
方案二:手动遍历实现
如果你不想依赖LINQ,也可以通过集合辅助遍历:
string[] array1 = {"apple", "banana", "cherry", "date"}; string[] array2 = {"banana", "date", "fig", "grape"}; HashSet<string> set2 = new HashSet<string>(array2); List<string> uniqueToFirst = new List<string>(); foreach (string item in array1) { if (!set2.Contains(item)) { uniqueToFirst.Add(item); } } string[] result = uniqueToFirst.ToArray();
2. 从SQL数据库中获取缺勤学生姓名的问题
看了你的代码,核心问题大概率出在字符串匹配不一致上——数据库里的RFID值和ListBox中的值可能存在格式差异(比如大小写、前后空格、中间空格数量不同),导致total.Remove(temp)无法正确匹配并移除元素。另外,直接遍历修改total列表的方式遇到重复项时,只会移除第一个匹配项,可靠性不足。
问题分析
- 数据库中
Rfid_Uid是nvarchar(1500)类型,可能存在前后空格,或者字母大小写与ListBox中的内容不一致(比如数据库存42 39 a0 11,ListBox显示42 39 A0 11) - 你的代码没有对RFID字符串做格式统一处理,直接进行匹配,自然容易失败
修复后的代码
我给你两种改进方案,优先推荐用LINQ简化逻辑,同时统一字符串格式:
方案一:用LINQ实现更可靠的逻辑
private void checkabst_Click(object sender, EventArgs e) { // 定义统一格式的方法:去除前后空格,转大写,确保匹配一致 Func<string, string> normalizeRfid = rfid => rfid?.Trim().ToUpper() ?? string.Empty; // 获取数据库中所有学生的RFID并统一格式 List<string> total; using (SqlConnection con = new SqlConnection(cs)) { SqlCommand cmd = new SqlCommand("Select Rfid_Uid From Studetails", con); con.Open(); SqlDataReader sdr = cmd.ExecuteReader(); total = new List<string>(); while (sdr.Read()) { string rfid = sdr[0].ToString(); total.Add(normalizeRfid(rfid)); } } // 获取ListBox中到校学生的RFID并统一格式 List<string> present = listbox_present.Items .Cast<string>() .Select(rfid => normalizeRfid(rfid)) .ToList(); // 计算缺勤学生的RFID:total中存在但present中没有的 List<string> absentRfids = total.Except(present).ToList(); // 补充获取缺勤学生姓名的逻辑(如果需要的是姓名而非RFID) List<string> absentNames = new List<string>(); using (SqlConnection con = new SqlConnection(cs)) { // 参数化查询避免SQL注入 string placeholders = string.Join(", ", absentRfids.Select((_, i) => $"@rfid{i}")); // 数据库中也统一格式进行匹配 SqlCommand cmd = new SqlCommand($"Select Name From Studetails Where UPPER(LTRIM(RTRIM(Rfid_Uid))) IN ({placeholders})", con); for (int i = 0; i < absentRfids.Count; i++) { cmd.Parameters.AddWithValue($"@rfid{i}", absentRfids[i]); } con.Open(); SqlDataReader sdr = cmd.ExecuteReader(); while (sdr.Read()) { absentNames.Add(sdr[0].ToString()); } } // 清空缺勤列表再添加新内容 listbox_absent.Items.Clear(); foreach (string name in absentNames) { listbox_absent.Items.Add(name); } }
方案二:修复你原来的遍历逻辑
如果你坚持用原来的遍历方式,记得先统一格式:
private void checkabst_Click(object sender, EventArgs e) { Func<string, string> normalizeRfid = rfid => rfid?.Trim().ToUpper() ?? string.Empty; List<string> total = new List<string>(); using (SqlConnection con = new SqlConnection(cs)) { SqlCommand cmd = new SqlCommand("Select Rfid_Uid From Studetails", con); con.Open(); SqlDataReader sdr = cmd.ExecuteReader(); while (sdr.Read()) { total.Add(normalizeRfid(sdr[0].ToString())); } } List<string> present = listbox_present.Items .Cast<string>() .Select(rfid => normalizeRfid(rfid)) .ToList(); // 筛选出缺勤的RFID,避免遍历修改列表的问题 List<string> absent = total.Where(rfid => !present.Contains(rfid)).ToList(); listbox_absent.Items.Clear(); foreach (string temp in absent) { listbox_absent.Items.Add(temp); } }
额外提示
- 如果最终需要的是缺勤学生的姓名,直接在SQL中查询会更高效,不需要先查所有RFID再对比——比如可以直接查询不在present列表中的学生姓名,减少内存占用和数据传输。
- 永远记得参数化SQL查询,避免SQL注入风险,上面的代码已经做了参数化处理。
- 调试时可以打印几个
total和present中的元素,快速确认格式是否一致,这是排查这类问题最直接的方式。
内容的提问来源于stack exchange,提问作者Venkatesh Shiga
相关产品推荐
相关产品推荐

