1

I have list of object and its relation.

public class Rack
{
    public string Name {get;set;}
    public List<Product> Products {get;set;}
}

public class Product
{
   public string Name {get;set;}
   public string Description {get;set;}
}

Now I am trying to make dictionary List of racks but with the key as Product Name and values as Racks ( product belonging to which all racks)

var allRacks = GetAllRacks(); // List of racks 
var dict = allRacks
                .SelectMany(rack => 
                    rack.Product.Select(prod => new 
                    { 
                        key = prod.Name, 
                        value = prod.Name, 
                    })
                ).ToDictionary(x => x.key, x => x.value);

But I get error as key are already added.

So how to select distinct key here or any other way to do that?

Rack   Product 
R1     P1,P2,P3 
R2     P3,P4 
R3     P2,P4

And output as dictionary 

P1     R1
P2     R1,R3
P3     R1
P4     R2,R3
CoreLean
  • 2,139
  • 5
  • 24
  • 43
  • can you post more relevant code, what type is allRacks here? – Phani Jun 13 '23 at 20:27
  • 1
    Group by Rack.Name. Also, use meaningful variable names (i.e. `rack` instead of `f`, `product` instead of `g`). Also, a [mre] would be good here. – Heretic Monkey Jun 13 '23 at 20:30
  • maybe this could help https://stackoverflow.com/questions/3319016/convert-list-to-dictionary-using-linq-and-not-worrying-about-duplicates – M.Ryan Jun 13 '23 at 20:36
  • 1
    *But I get error as key are already added* Yes, this is unavoidable if two of your racks end up mapping to the same product name, because a dictionary will only allow the product name to appear once. Perhaps you should use a [`Lookup`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.lookup-2?view=net-7.0) instead of a dictionary. A `Lookup` can contain several racks for a single product name. – John Wu Jun 13 '23 at 20:37
  • Result should be a `Dictionary>`? – Ralf Jun 13 '23 at 20:39
  • I am trying to create product as key which will be in many rack. – CoreLean Jun 13 '23 at 20:40
  • @Ralf , yes. string ( product Name) and value as List – CoreLean Jun 13 '23 at 20:41

3 Answers3

2

Since you want to access your values with multiple results per key you should actually be using ToLookup (ILookup<string, List<Rack>>) here

var allRacks = GetAllRacks();
var dict = allRacks.SelectMany(f => f.Product.Select(g => new { key = g.Name, value = f.Name }))
                   .ToLookup(f => f.key, f => f.value);

Or if you are for some reason insist on Dictionary<string, List<Rack>> works like this:

var dict = allRacks
   .SelectMany(rack => rack.Products.Select(product => (product, rack)))
   .GroupBy(d => d.product.Name, (s, tuples) => (productName: s, racks : tuples.Select(d => d.rack).ToList()))
   .ToDictionary(d => d.productName, d=> d.racks);
Dbl
  • 5,634
  • 3
  • 41
  • 66
  • 1
    Presumably `value = f.Name` should be just `value = f` as he wanted to find a rack not just the name of the rack. – Ralf Jun 13 '23 at 21:03
  • 1
    Thanks @Dbl. All other solution worked provided by others but your first options is simple and worked as expected (lookup). – CoreLean Jun 14 '23 at 18:27
1

You can't have duplicated keys within Dictionary<TKey, TValue>, so you should GroupBy all records by product Name and then turn grouping into the dictionary:

var dict = GetAllRacks()
  .SelectMany(rack => rack
     .Products
     .Select(product => (product : product.Name, rack : rack)))
  .GroupBy(pair => pair.product, pair => pair.rack)
  .ToDictionary(group => group.Key, group => group.ToList());
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
1

You probably have duplicate names. Try following :

List<Rack> allRacks = GetAllRacks(); 
Dictionary<string, List<Rack>>  dict = 
        allRacks.SelectMany(f => f.Products.Select(g => new 
                            { 
                                key = g.Name, 
                                rack = f,
                            })
                ).GroupBy(x => x.key, y => y.rack)
                .ToDictionary(x => x.Key, y => y.ToList());
jdweng
  • 33,250
  • 2
  • 15
  • 20