简体   繁体   English

使用LINQ对存储在一维数组中的记录进行分组

[英]Group records stored in one-dimensional array using LINQ

I have a situation, where I get data from the database in such a way, that everything is stored in one-dimensional array. 我有一种情况,我以这种方式从数据库中获取数据,所有内容都存储在一维数组中。
For example: 例如:

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

As a result of joining these tables I obtain array of the following form: 连接这些表的结果是,我获得了以下形式的数组:

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

I know it's not a good solution of keeping data, but these data are coming to me from some other piece of code which I am not allowed to change, so I have to deal with it. 我知道这不是保存数据的好方法,但是这些数据是从其他一些我无法更改的代码中获取的,因此我必须加以处理。

My questions are: 我的问题是:

  1. Is this possible to use LINQ in order to parse this array and place data in my own objects (User class with Groups collection in it). 是否可以使用LINQ来解析此数组并将数据放置在我自己的对象(其中包含Groups集合的User类)中。
  2. What is other best way to handle it if not by LINQ? 如果不使用LINQ,还有什么其他最好的处理方式?

Pure linq Expression : 纯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()});
  • In the first GroupBy I group results in 4 elements subsets using a floor and a temporary variable. 在第一个GroupBy我使用下限和临时变量对4个元素子集进行分组。
  • Then The next Select put the resulting arrays in an anonymous type for better usability in the next steps. 然后,下一个Select将结果数组放入匿名类型,以在下一步中提供更好的可用性。
  • The next GroupBy is used to group the entries by Employee. 下一个GroupBy用于按Employee对条目进行分组。 The Key will be the employee and the values will be the corresponding Groups. 关键字将是员工,值将是相应的组。
  • Finaly the lase Select is used to put the GroupBy result in a better shape. 最后,使用lase Select来使GroupBy结果具有更好的形状。 I choose to put the result in an other anonymous type but You could instantiate you custom objects here and put the values in the right fields using curly brace constructor. 我选择将结果放入其他匿名类型中,但是您可以在此处实例化自定义对象,并使用花括号构造函数将值放在正确的字段中。

If your logic depends on indexes LINQ is is rarely the right tool. 如果您的逻辑依赖于索引,则LINQ几乎不是正确的工具。 It results in less readable, maintainable, efficient and robust code than with plain loops. 与普通循环相比,它导致可读性,可维护性,效率和鲁棒性较低的代码。

I would use something like following to create two dictionaries representing the many to many relation. 我将使用类似以下内容的方法来创建两个表示多对多关系的字典。 Note the for -loop which increments by 4 on every iteration since that seems to be the user-group-"package": 请注意for -loop,它在每次迭代时增加4,因为这似乎是user-group-“ package”:

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 });
    }
}

The result is: 结果是:

  • the user-dictionary contains one user with two groups 用户词典包含一个有两个组的用户
  • the group-dictionary contains two groups which map to the same user 组字典包含两个映射到同一用户的组

You have to override Equals and GetHashCode to compare the ID's: 您必须重写EqualsGetHashCode来比较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;
    }
}

You can do it with the basic structures like loops: 您可以使用像循环这样的基本结构来做到这一点:

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

Output: 输出:

在此处输入图片说明

Please take advise: this code does not contain any validation logic, or duplicate checks. 请注意:此代码不包含任何验证逻辑或重复检查。 You'll have to imlpement this by yourself. 您必须自己植入。 But before you implement something like this, I'd rather change the way you get your data delivered. 但是,在实施此类操作之前,我宁愿更改数据交付方式。 this way you would deal with the root of your peroblems not with the symptoms. 这样,您就可以解决困扰的根源而不是症状。

i think no need to linq 我认为没有必要

//some class //一些类

    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;}

    }

// your array //您的数组

    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);


    }

// simple cast array to some type //将简单的转换数组转换为某种类型

    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] };
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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