【问题标题】:Group records stored in one-dimensional array using LINQ使用 LINQ 将存储在一维数组中的记录分组
【发布时间】:2014-09-26 11:07:13
【问题描述】:

我有一种情况,我从数据库中获取数据的方式是,所有内容都存储在一维数组中。
例如:

User table: UserId, Name
Group table: GroupId, Name
UserGroup table: UserId, GroupId

作为连接这些表的结果,我获得了以下形式的数组:

result[0] = "1" // user id
result[1] = "John Doe" // user name
result[2] = "121" // group id
result[3] = "SomeGroup" // group name
result[4] = "1" // user id
result[5] = "John Doe" // user name
result[6] = "2135" // group id
result[7] = "SomeOtherGroup" // group name

我知道这不是保存数据的好解决方案,但是这些数据来自其他一些我不允许更改的代码,所以我必须处理它。

我的问题是:

  1. 是否可以使用 LINQ 来解析此数组并将数据放入我自己的对象(其中包含 Groups 集合的用户类)。
  2. 如果不是 LINQ,还有什么其他最好的方法来处理它?

【问题讨论】:

  • 所以一个用户可以属于多个组(在这种情况下会重复用户)。所有用户所属的组是否也对每个用户重复?
  • 这是多对多的关系。一个用户可以属于多个组,一个组可以包含多个用户。
  • 那么如何区分用户和组?
  • 可能仅通过索引和重复模式
  • 我只知道查询结果显示了多少列。我知道包含此结果数组的对象的 RowCount 和 ColumnCount 属性。因此,例如要获取我使用的第 i 个记录的组名:result[i * ColumnCount + 3]。

标签: c# sql arrays linq


【解决方案1】:

纯 linq 表达式:

int i = 0;
var objects = result.GroupBy(x => Math.Floor(i++ / 4.0))
            .Select(g => new { id =g.ElementAt(0), name = g.ElementAt(1), gId= g.ElementAt(2), group = g.ElementAt(3)})
            .GroupBy(x=>new {x.id, x.name}, x=>new {x.gId, x.group})
            .Select(y=>new {y.Key, groups = y.ToList()});
  • 在第一个 GroupBy 中,我使用地板和临时变量将结果分组为 4 个元素子集。
  • 然后下一个Select 将生成的数组放入匿名类型中,以便在接下来的步骤中更好地使用。
  • 下一个GroupBy 用于按员工对条目进行分组。键是员工,值是相应的组。
  • 最后,Select 用于使GroupByresult 的形状更好。我选择将结果放入其他匿名类型,但您可以在此处实例化自定义对象并使用花括号构造函数将值放入正确的字段中。

【讨论】:

  • 您需要添加int i = 0;。没有它就无法编译
  • 您的解决方案很棒!谢谢你。您会如此友善和耐心地逐步解释它是如何工作的吗?我真的不明白会发生什么。
  • 是的,我会修改我的答案
  • 这个查询失败的原因有十几个 ;-)
  • @TimSchmelter 我认识我的朋友。我看到两个主要的:result.Lenght % 4 != 0 和 result.Any(x=>x == null)。两者都可以通过一些预先检查来避免:P
【解决方案2】:

如果您的逻辑依赖于索引 LINQ 很少是正确的工具。与普通循环相比,它会导致代码的可读性、可维护性、效率和健壮性更低。

我会使用以下内容来创建两个表示多对多关系的字典。请注意 for-loop 每次迭代都会增加 4,因为这似乎是用户组-“包”:

var userIdGroups = new Dictionary<int, HashSet<Group>>();
var groupIdUsers = new Dictionary<int, HashSet<User>>();

for(int i = 0; i < result.Length; i += 4)
{
    int id;
    if(int.TryParse(result[i], out id))
    {
        string name = result.ElementAtOrDefault(i + 1);
        if(name == null)
            continue; // end, invalid data

        User user = new User{ UserId = id, Name = name };
        string groupID = result.ElementAtOrDefault(i + 2);
        if(!int.TryParse(groupID, out id))
            continue; // end, invalid data

        name = result.ElementAtOrDefault(i + 3);
        if(name == null)
            continue; // end, invalid data

        Group group = new Group{ GroupId = id, Name = name };
        HashSet<Group> userGroups;
        HashSet<User> groupUsers;
        if (userIdGroups.TryGetValue(user.UserId, out userGroups))
            userGroups.Add(group);
        else
            userIdGroups.Add(user.UserId, new HashSet<Group>{ group });

        if (groupIdUsers.TryGetValue(group.GroupId, out groupUsers))
            groupUsers.Add(user);
        else
            groupIdUsers.Add(group.GroupId, new HashSet<User> { user });
    }
}

结果是:

  • 用户词典包含一个用户和两个组
  • 组字典包含映射到同一用户的两个组

您必须覆盖 Equals 和 GetHashCode 才能比较 ID:

class User
{
    public int UserId { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        User u2 = obj as User;
        if (u2 == null) return false;
        return UserId == u2.UserId;
    }
    public override int GetHashCode()
    {
        return UserId;
    }
}
class Group
{
    public int GroupId { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        Group g2 = obj as Group;
        if (g2 == null) return false;
        return GroupId == g2.GroupId;
    }
    public override int GetHashCode()
    {
        return GroupId;
    }
}

【讨论】:

    【解决方案3】:

    你可以用循环之类的基本结构来做到这一点:

    void Main()
    {
        var result = new string[] {"1","John Doe","2","Joes Group","3","Jack Daniel","4","Jacks Group","5","Foo Bar","6","FooBar Group",};
        List<Person> personList = new List<Person>();
        List<Group> groupList = new List<Group>();
    
        for(int i = 0; i < result.Length; i+=2) 
        {
            i = i + 2;
            //check if group does not already exist
            groupList.Add(new Group() {Name = result[i+1]});
        }
    
        for(int i = 0; i < result.Length; i+=2)
        {
            //check if person exists.
            //if person only add group to person personList.Where(x => x.Name ==result[i+1])....
            personList.Add(new Person() { Id = int.Parse(result[i]), 
                                          Name = result[i+1],
                                          Groups = new List<Group>()
                                          {
                                            groupList.FirstOrDefault (l => l.Name == result[i+3])
                                          }
                                        });
            i = i+2;    
        }
    
        personList.Dump();
    }
    
    public class Person
    {
        public Person()
        {
            Groups = new List<Group>();
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Group> Groups { get; set; }
    
    }
    
    public class Group
    {
        public string Name { get; set; }
    }
    // Define other methods and classes here
    

    输出:

    请注意:此代码不包含任何验证逻辑或重复检查。你必须自己实现这一点。 但在你实施这样的事情之前,我宁愿改变你获取数据的方式。这样你就可以解决问题的根源而不是症状。

    【讨论】:

      【解决方案4】:

      我认为不需要 linq

      //某类

          public class Result
          {    
              public string UserId {get;set;}
              public string UserName {get;set;}
              public string GroupId {get;set;}
              public string GroupName {get;set;}
              public string UserGroupUserId {get;set;}
              public string UserGroupUserName {get;set;}
              public string UserGroupId {get;set;}
              public string UserGroupGroupId {get;set;}
      
          }
      

      // 你的数组

          private void Form1_Load(object sender, EventArgs e)
           {
              string[] result = new string[8];
              result[0] = "1";
              result[1] = "John Doe";
              result[2] = "121";
              result[3] = "SomeGroup";
              result[4] = "1";
              result[5] = "John Doe";
              result[6] = "2135";
              result[7] = "SomeOtherGroup";
      
      
      
              Result r = CastResult(result);
      
      
          }
      

      // 将数组简单转换为某种类型

          public Result CastResult(string[] array)
          {
              return new Result() { UserId=array[0], UserName=array[1], GroupId=array[2], GroupName=array[3], UserGroupUserId=array[4], UserGroupUserName=array[5] , UserGroupId=array[6], UserGroupGroupId=array[7] };
          }
      

      【讨论】:

        猜你喜欢
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 2020-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-12
        • 1970-01-01
        相关资源
        最近更新 更多