簡體   English   中英

使用LINQ對存儲在一維數組中的記錄進行分組

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

我有一種情況,我以這種方式從數據庫中獲取數據,所有內容都存儲在一維數組中。
例如:

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集合的User類)中。
  2. 如果不使用LINQ,還有什么其他最好的處理方式?

純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用於按Employee對條目進行分組。 關鍵字將是員工,值將是相應的組。
  • 最后,使用lase Select來使GroupBy結果具有更好的形狀。 我選擇將結果放入其他匿名類型中,但是您可以在此處實例化自定義對象,並使用花括號構造函數將值放在正確的字段中。

如果您的邏輯依賴於索引,則LINQ幾乎不是正確的工具。 與普通循環相比,它導致可讀性,可維護性,效率和魯棒性較低的代碼。

我將使用類似以下內容的方法來創建兩個表示多對多關系的字典。 請注意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 });
    }
}

結果是:

  • 用戶詞典包含一個有兩個組的用戶
  • 組字典包含兩個映射到同一用戶的組

您必須重寫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;
    }
}

您可以使用像循環這樣的基本結構來做到這一點:

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

輸出:

在此處輸入圖片說明

請注意:此代碼不包含任何驗證邏輯或重復檢查。 您必須自己植入。 但是,在實施此類操作之前,我寧願更改數據交付方式。 這樣,您就可以解決困擾的根源而不是症狀。

我認為沒有必要

//一些類

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM