繁体   English   中英

从数据表C#中分组后字典中的多个键

[英]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;

假设您不希望将StudentIdStudentTempId作为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具有上述属性,即StudentIdStudentTempId那么可以通过执行以下操作来获取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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM