Search code examples
c#linqgrouping

Linq group by condition


I provide the simple list as below :

var records = new List<BookRecord> {
            new() {
                Author = "Peter",
                BookName = "Book A"
            },
            new() {
                Author = "",
                BookName = "Book B"
            },
            new() {
                Author = "Peter",
                BookName = "Book C"
            },
            new() {
                Author = "James",
                BookName = ""
            },
            new() {
                Author = "",
                BookName = "Book D"
            },
            new() {
                Author = "James",
                BookName = ""
            },
            new() {
                Author = "",
                BookName = "Peter"
            }
        };

I want to group only author is not empty (or other condition) , and the remain need to keep into result , so my expected result will be :

[
  {"Author":"Peter","BookName":"Book A"},
  {"Author":"","BookName":"Book B"},
  {"Author":"James","BookName":""},
  {"Author":"","BookName":"Book D"},
  {"Author":"","BookName":"Peter"}
]

and need to in ordering (that mean "james" should be row 3 and the last one must be {"Author":"","BookName":"Peter"}

can I know how to do it ?

Thank you


Solution

  • As far as I can see you want

    1. If Author is set (not an empty string) return his/her first book only.
    2. If Author is not set just return the record.

    If it's your case, you can either GroupBy followed by Select + First:

    int index = 0;
    
    var result = source
      .GroupBy(item => (item.Author, string.IsNullOrEmpty(item.Author) ? ++index : 0))
      .Select(group => group.First())
      .ToList(); // if you want it as a list
    

    The trick is to make all groups with empty Author being unique which we do with a help of index.

    If we don't want to use side effects with index we can exploit the same idea but with longer query:

    var result = source
      .Select((value, index) => (value, index))
      .GroupBy(pair => (pair.value.Author, string.IsNullOrEmpty(pair.value.Author) 
                          ? pair.value.index 
                          : 0),
               pair => pair.value)
      .Select(group => group.First())
      .ToList(); // if you want it as a list