![](/img/trans.png)
[英]Remove multiple keys with same value data from dictionary in C# using Linq
[英]Multiple keys in dictionary after group by from data table c#
我目前正在从Excel中提取多个列。
Excel格式如下
StudentId StudentTempId Department Address TotalMarks
1 100 IT Brooklyn 90
1 100 IT Manhattan 80
2 200 HR Boston 50
一个学生可以有多个地址,这就是为什么从excel提取数据到数据表后,我首先应用group by,然后将其转换为字典。 我在2列StudentId和StudentTempId上应用了该组。 因此,在转换为字典时会创建两个键。 现在,我创建了一个具有相同两项的元组,其余三个字段以StudentDetail类的形式添加到dictionary的值中,如下所示:
public class StudentDetail
{
public string Department { get; set; }
public string Address { get; set; }
public int TotalMarks { get; set; }
}
下面我编写的代码将对象中的所有excel数据填充:
Dictionary<Tuple<int, int>, List<StudentDetail>> StudentDetailList
= dataTable.AsEnumerable()
.GroupBy(row => Tuple.Create
(
row.Field<int>("StudentId"),
row.Field<int>("StudentTempId")
)).
ToDictionary
(
dict => dict.Key,
dict => dict.Select(row => new StudentDetail
{
Department = row.Field<string>("Department"),
Address = row.Field<string>("Address"),
TotalMarks = row.Field<int>("TotalMarks")
}).ToList()
);
除了使用Tuple作为键组合之外,还有其他什么好方法吗?
有什么帮助吗?
使用UInt64作为键,使用位移将元组的整数组合在一起。
Dictionary<UInt64, List<StudentDetail>> StudentDetailList
= dataTable.AsEnumerable()
.GroupBy(row => new UInt64(
(UInt64)(row.Field<int>("StudentId"))<< 32 |
(UInt64)(row.Field<int>("StudentTempId"));
)).
ToDictionary
(
dict => dict.Key,
dict => dict.Select(row => new StudentDetail
{
Department = row.Field<string>("Department"),
Address = row.Field<string>("Address"),
TotalMarks = row.Field<int>("TotalMarks")
}).ToList()
);
按位运算是现代处理器所固有的,应该可以显着提高性能(假设使用64位进程并且没有负值)。 要分离密钥,如果需要,请使用以下代码:
int StudentId = key >> 32;
int StudentTempId = key && 0xFFFFFFFF;
假设您不希望将StudentId
和StudentTempId
作为StudentDetail
模型的一部分,那么我想说这是一个好方法,因为您可以通过以下方式简单地获取给定键的对应列表:
var studentDetails = StudentDetailList[Tuple.Create(1, 100)];
您可以通过对ValueTuple
进行分组来使语法更好ValueTuple
即
.GroupBy(row => (row.Field<int>("StudentId"),
row.Field<int>("StudentTempId")))
在这种情况下,您可以按以下方式访问它:
var studentDetails = StudentDetailList[(1, 100)];
但是,如果您可以在StudentDetail
具有上述属性,即StudentId
和StudentTempId
那么可以通过执行以下操作来获取List<IEnumerable<StudentDetail>>
:
var studentDetails = dataTable.AsEnumerable()
.GroupBy(row =>
(
row.Field<int>("StudentId"),
row.Field<int>("StudentTempId")
)).Select(g => g.Select(row => new StudentDetail
{
StudentId = g.Key.Item1,
StudentTempId = g.Key.Item2,
Department = row.Field<string>("Department"),
Address = row.Field<string>("Address"),
TotalMarks = row.Field<int>("TotalMarks")
})).ToList();
每当您需要查找特定的一组学生详细信息时,都可以通过以下方式对其进行查询:
var result = studentDetails.SingleOrDefault(s => s.Any(e => e.StudentId == 1 && e.StudentTempId == 100));
或使用FirstOrDefault
取决于您最合适的选择:
var result = studentDetails.FirstOrDefault(s => s.Any(e => e.StudentId == 1 && e.StudentTempId == 100));
Tuple
对于组合键很有用,因为它的GetHashCode
实现实际上使用了所有值来生成哈希码。 对于ValueTuple
也是如此。
您要避免使用的是结构而不覆盖GetHashCode
因为它将使用ValueType
定义的实现,该实现只是从结构中的第一个值调用GetHashCode
。 如果多个键的值与其第一个成员相同,则可能会导致很多冲突。 这不会破坏您的代码,但会降低字典的性能。
您可以在此处查找这些实现: https : //referencesource.microsoft.com
如果您使用的是C#7.0或更高版本,我建议您使用ValueTuple
,因为有一个文字可以使用。 https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-tuples/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.