score:3

Accepted answer

With LINQ you can do like this:

var groupedByAuthor = list
    .SelectMany(publication => 
        publication.Authors.Select(author => new { author, publication }))
    .GroupBy(arg => arg.author, keyValue => keyValue.publication)
    .ToArray();

But this will be a little bit slower.

score:0

You can use Linq and some anonymous classes:

public class Publication
{
    public List<string> Authors { get; set; }

    public string Title { get; set; }
}

class Program
{
    static void Main()
    {
        IEnumerable<Publication> publications; // YOUR DATA HERE!

        var groupsByAuthor = publications.SelectMany(publication => publication.Authors.Select(author => new { Publication = publication, Author = author })).GroupBy(x => x.Author);

        foreach (var gba in groupsByAuthor)
        {
            Console.WriteLine(gba.Key);
            foreach (var pub in gba)
            {
                Console.WriteLine(pub.Publication.Title);
            }
        }

        Console.ReadLine();
    }
}

score:-1

You can also do it like this :

var dict = pubs.SelectMany(p => p.Authors)
               .ToDictionary(
                   a => a, 
                   a => pubs.Where(p => p.Contains(a)).ToList())
               );

Not tested but you get the idea.

score:0

If you more concerned about clean and expressive code you may want to try creating an extension method instead brute forcing an ugly linq query. Code should look something like the following.

class Program
{
    static void Main(string[] args)
    {
        List<Publication> test = new List<Publication>();
        Dictionary<string, List<Publication>> publicationsByAuther = test.GroupByAuthor();
    }
}


public static class Extensions
{

    public static Dictionary<string, List<Publication>> GroupByAuther(this List<Publication> publications)
    {
        Dictionary<string, List<Publication>> dict = new Dictionary<string, List<Publication>>();
        foreach (var publication in publications)
        {
            foreach (var author in publication.Authors)
            {
                if (dict.ContainsKey(author))
                {
                    dict[author].Add(publication);
                }
                else
                {
                    dict.Add(author, new List<Publication>
                {
                    publication
                });
                }
            }
        }
        return dict;
    }
}

score:0

You might think about separating the case of adding a new author from adding a publication. Turning the code into something like that:

var dict = new Dictionary<string, List<Publication>>();
foreach (var publication in list)
{
    foreach (var author in publication.Authors)
    {
        if (!dict.ContainsKey(author))
            dict.Add(author, new List<Publication>());
        dict[author].Add(publication);
    }
}

It is not LINQ and not a new solution, but maybe it can help about the elegancy


Related Articles