代码之家  ›  专栏  ›  技术社区  ›  Phate01

将2个集合聚合到父/子集合

  •  -1
  • Phate01  · 技术社区  · 6 年前

    我不确定我找到的解决这个问题的方法是不是一个好方法。

    示例场景:

    类folderItem
    {
    public int id_get;set;
    公共字符串名称get;set;
    public fileitem[]文件获取;设置;
    }
    
    类文件项
    {
    public int id_get;set;
    public int folderid_get;set;
    公共字符串名称get;set;
    公共字节[]内容获取;设置;
    }
    

    从2个集合开始:

    文件夹= 新文件夹项目[] { 新文件夹项目 { ID=1, name=“folder1” },请 新文件夹项目 { ID=2, name=“folder2” } }(二) 文件项[]文件= 新建文件项[] { 新建文件项 { ID=100, folderID=1, name=“file1.txt”, 内容=新字节[]1、2、3 },请 新建文件项 { ID=200, folderID=1, name=“file2.txt”, 内容=新字节[]1、2、3 },请 新建文件项 { ID=300, folderID=2, name=“file3.txt”, 内容=新字节[]1、2、3 },请 新建文件项 { ID=400, folderID=2, name=“file4.txt”, 内容=新字节[]1、2、3 } }(二)

    为了将“fileitem”放入“folder”的属性“files”,我需要:

    文件
    .加入
    (
    文件夹,
    x=>x.folderid,文件夹ID,
    x=>x.标识,
    (x,y)=>新建文件=x,文件夹=y
    )
    .groupby(x=>x.folder.id)
    .选择
    (x=>
    {
    var folder=x.first().folder;
    folder.files=x.select(z=>z.file).toarray();
    返回文件夹;
    }
    )
    

    我可以在groupbylambda中使用first()because I'm grouping by its id

    我得到:

    有没有比这更快更好的扩展方法?有什么最佳实践吗?

    从2个集合开始:

    FolderItem[] folders = 
        new FolderItem[]
        {
            new FolderItem
            {
                Id = 1,
                Name = "Folder1"
            },
            new FolderItem
            {
                Id = 2,
                Name = "Folder2"
            }
        };
    
    FileItem[] files = 
        new FileItem[]
        {
            new FileItem
            {
                Id = 100,
                FolderId = 1,
                Name = "file1.txt",
                Content = new byte[] { 1, 2, 3 }
            },
            new FileItem
            {
                Id = 200,
                FolderId = 1,
                Name = "file2.txt",
                Content = new byte[] { 1, 2, 3 }
            },
            new FileItem
            {
                Id = 300,
                FolderId = 2,
                Name = "file3.txt",
                Content = new byte[] { 1, 2, 3 }
            },
            new FileItem
            {
                Id = 400,
                FolderId = 2,
                Name = "file4.txt",
                Content = new byte[] { 1, 2, 3 }
            }
        };
    

    为了将“fileitem”放入“folder”的“files”属性中,我需要:

     files
        .Join
        (
            folders,
            x => x.FolderId,
            x => x.Id,
            (x,y) => new { File = x, Folder = y }
        )
        .GroupBy(x => x.Folder.Id)
        .Select
        (x => 
            { 
                var folder = x.First().Folder;
                folder.Files = x.Select(z => z.File).ToArray();
                return folder;
            }
        )
    

    我可以用.First()GroupBylambda,因为我按其ID分组

    我得到:

    enter image description here

    有没有比这更快更好的扩展方法?有什么最佳实践吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   John Wu    6 年前

    只需创建一个新列表,使用 Where 获取每个文件夹的文件。

    var foldersWithFiles = folders
        .Select
        (
            folder =>
            new FolderItem
            {
                Id = folder.Id,
                Name = folder.Name,
                Files = files.Where
                (
                    file => file.FolderId = folder.Id
                ).ToArray()
            )
        );
    

    您可以在以后替换旧列表,如下所示:

    folders = foldersWithFiles.ToArray();
    
        2
  •  1
  •   Franck    6 年前

    您可以简单地循环文件夹并将项目添加到各自的文件夹中。 首先你需要换衣服 FileItem[] 进入之内 List<FileItem> FolderItem[] 进入之内 List<FolderItem> 到处都是。

    您需要一个remove和get扩展方法 List 就像这个。这是为了在返回元素的同时删除元素,从而减少 随后的迭代。

    public static List<T> RemoveAndGet<T>(this List<T> list, Func<T, bool> predicate)
    {
        var itemsRemoved = new List<T>();
    
        // iterate backward for performance
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // keep item pointer
            var item = list[i];
    
            // if the item match the remove predicate
            if (predicate(item))
            {
                // add the item to the returned list
                itemsRemoved.Add(item);
    
                // remove the item from the source list
                list.RemoveAt(i);
            }
        }
    
        return itemsRemoved;
    }
    

    然后,您唯一的查询就是用这个查询填充当前的文件夹。

     folders.ForEach(folder => 
         folder.Files.AddRange(files.RemoveAndGet(file => file.FolderId == folder.Id)));