C#-将多对多的对象列表分解为两个对象列表的不同组合的列表

问题描述 投票:1回答:2

我似乎无法掌握如何执行此操作,也找不到一种简单的方法来解释它,所以我希望这个简化的示例有意义。

被赋予对象的列表<>:

public class FlatManyToMany
{
    public string BookTitle { get; set; }
    public string BookPages { get; set; }
    public string ReaderName { get; set; }
    public string ReaderAge { get; set; }
}

var flatManyToMany = new List<FlatManyToMany>();

flatManyToMany.Add(new FlatManyToMany { BookTitle = "How to Do This Double List", BookPages = 105, ReaderName = "Kyle", ReaderAge = 29 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "How to Do This Double List", BookPages = 105, ReaderName = "Bob", ReaderAge = 34 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Gone With Jon Skeet", BookPages = 192, ReaderName = "Kyle", ReaderAge = 29 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Gone With Jon Skeet", BookPages = 192, ReaderName = "James", ReaderAge = 45 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Gone With Jon Skeet", BookPages = 192, ReaderName = "Brian", ReaderAge = 15 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Why Is This So Hard?", BookPages = 56, ReaderName = "Kyle", ReaderAge = 29 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Why Is This So Hard?", BookPages = 56, ReaderName = "James", ReaderAge = 45 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Why Is This So Hard?", BookPages = 56, ReaderName = "Brian", ReaderAge = 15 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Impostor Syndrome", BookPages = 454, ReaderName = "Kyle", ReaderAge = 29 });
flatManyToMany.Add(new FlatManyToMany { BookTitle = "Self Doubt and You", BookPages = 999, ReaderName = "Kyle", ReaderAge = 29 });

我需要的结果是这样的两个对象列表的列表:

public class ResultDoubleList
{
    public List<Book> Books { get; set; } = new List<Book>();
    public List<Reader> Readers { get; set; } = new List<Reader>();
}

public class Book
{
    public string Title { get; set; }
    public int Pages { get; set; }
}

public class Reader
{
    public string Name { get; set; }
    public int Age { get; set; }
}

该书在最终结果中只显示一次,但是读者可以显示多次。如果同一位读者阅读了多本书,则可以放在一起。

这是我需要结果的方式:

List<ResultDoubleList> results = new List<ResultDoubleList>();

result(1):
Books
    How to Do This Double List  105
Readers
    Kyle    29
    Bob     34

result(2):
Books
    Gone With Jon Skeet     192
    Why Is This So Hard?    56
Readers
    Kyle    29
    James   45
    Brian   15

result(3):
Books
    Impostor Syndrome   454
    Self Doubt and You  999
Readers
    Kyle    29

因此,书籍清单和读者清单的不同组合是最终结果。该书仅显示一次,但读者可以显示多次。具有完全相同的读者列表的书籍将被分组在一起。

即使有人可以告诉我这种最终结果的名称,我也很感激。

c# list linq loops
2个回答
0
投票

书籍和读者

var books = actsOfReading.GroupBy( a => a.BookTitle )
        .Select( g => new Book{Title = g.Key, Pages = g.Max(b => b.BookPages)})
        .ToList();

var readers = actsOfReading.GroupBy( a => a.ReaderName )
        .Select( g => new Reader{Name = g.Key, Age = g.Max(b => b.ReaderAge)})
        .ToList();

测试

var books = actsOfReading.GroupBy( a => a.BookTitle )
        .Select( g => new Book{Title = g.Key, Pages = g.Max(b => b.BookPages)})
        .ToList();

var readers = actsOfReading.GroupBy( a => a.ReaderName )
        .Select( g => new Reader{Name = g.Key, Age = g.Max(b => b.ReaderAge)})
        .ToList();

        var o = new System.Text.Json.JsonSerializerOptions{WriteIndented =true};

        Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(books,o));
        Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(readers,o));

输出

(手动格式化)

[
 { "Title": "How to Do This Double List", "Pages": 105 },
 { "Title": "Gone With Jon Skeet", "Pages": 192 },
 { "Title": "Why Is This So Hard?", "Pages": 56 },
 { "Title": "Impostor Syndrome", "Pages": 454 },
 { "Title": "Self Doubt and You", "Pages": 999 }
]
[
 { "Name": "Kyle", "Age": 29 },
 { "Name": "Bob", "Age": 34 },
 { "Name": "James", "Age": 45 },
 { "Name": "Brian", "Age": 15 }
]

0
投票

您可以使用这个冗长的LINQ查询来做到这一点:

var result = flatManyToMany
    .GroupBy(f1 => (f1.BookTitle, f1.BookPages))
    .Select(g1 => (bookInfo: g1.Key,
                    readers:
                        g1.Select(f2 => new Reader { Name= f2.ReaderName, Age= f2.ReaderAge }),
                    readerKey:
                        String.Join("|", g1.Select(f3 => $"{f3.ReaderName},{f3.ReaderAge}"))))
    // So far we have an:
    // IEnumerable<((string BookTitle, int BookPages) bookInfo, 
    //    IEnumerable<Reader> readers, string readerKey)>
    .GroupBy(a1 => a1.readerKey)
    .Select(g2 => new ResultDoubleList {
        Books = g2.Select(a2 => new Book {
            Title = a2.bookInfo.BookTitle,
            Pages = a2.bookInfo.BookPages
        }
            ).ToList(),
        Readers = g2.First().readers.ToList()
    })
    .ToList();

这个想法是分组两次。每本书一次,每个读者一次。

此测试...

int resultNo = 1;
foreach (ResultDoubleList item in result) {
    Console.WriteLine($"\r\nresult({resultNo++}):");
    Console.WriteLine("Books");
    foreach (var book in item.Books) {
        Console.WriteLine($"    {book.Title,-28} {book.Pages,3}");
    }
    Console.WriteLine("Readers");
    foreach (var reader in item.Readers) {
        Console.WriteLine($"    {reader.Name,-8} {reader.Age,2}");
    }
}
Console.ReadKey();

...产量:

result(1):
Books
    How to Do This Double List   105
Readers
    Kyle     29
    Bob      34

result(2):
Books
    Gone With Jon Skeet          192
    Why Is This So Hard?          56
Readers
    Kyle     29
    James    45
    Brian    15

result(3):
Books
    Impostor Syndrome            454
    Self Doubt and You           999
Readers
    Kyle     29
© www.soinside.com 2019 - 2024. All rights reserved.