Matias Cicero
Matias Cicero

Reputation: 26301

Mapping complex object to dictionary using LINQ

Consider the following object:

Controller controller = new Controller()
{
    Name = "Test",
    Actions = new Action[]
    {
        new Action() { Name = "Action1", HttpCache = 300 },
        new Action() { Name = "Action2", HttpCache = 200 },
        new Action() { Name = "Action3", HttpCache = 400 }
    }
};

How can I map this object to a dictionary of the following form?

#key# -> #value#
"Test.Action1" -> 300
"Test.Action2" -> 200
"Test.Action3" -> 400

That is, a Dictionary<string, int>.

I am interested in a LINQ solution but I can't manage to work around it.

I am trying to map each action to a KeyValuePair, but I don't know how to get each action's parent controller's Name property.

Upvotes: 4

Views: 952

Answers (4)

Amy B
Amy B

Reputation: 110171

The main thing is the controller is still in scope in the lambda:

var result = controller.Actions.ToDictionary(
  a => string.Format("{0}.{1}", controller.Name, a.Name),
  a => a.HttpCache);

Upvotes: 6

Cyril Durand
Cyril Durand

Reputation: 16192

You can try this :

var dico = controller.Actions
                     .ToDictionary(a => $"{controller.Name}.{a.Name}", 
                                   a => a.HttpCache);

The first lambda expression target the key whereas the second target the value of the dictionary entry.

Upvotes: 1

Avner Shahar-Kashtan
Avner Shahar-Kashtan

Reputation: 14700

The LINQ approach is to project the Actions list, using the Select method, into a dictionary. Since you're calling it on a Controller instance, you have access to the Controller's Name as well:

myController.Actions.ToDictionary(
    /* Key selector - use the controller instance + action */
    action => myController.Name + "." + action.Name, 
    /* Value selector - just the action */
    action => action.HttpCache);

If you want to make one large dictionary from several controllers, you can use SelectMany to project each Controller's items into a list of Controller+Action, then convert that list into a dictionary:

var namesAndValues = 
    controllers.SelectMany(controller =>
        controller.Actions.Select(action =>
            { 
              Name = controller.Name + "." + action.Name,
              HttpCache = action.HttpCache
            }));
var dict = namesAndValues.ToDictionary(nav => nav.Name, nav => nav.HttpCache); 

Upvotes: 1

Dr. Wily&#39;s Apprentice
Dr. Wily&#39;s Apprentice

Reputation: 10280

Assuming that you have multiple controllers in a collection, not just the one controller variable in your example code, and want to put all of their actions into a single dictionary, then you could do something like this:

var httpCaches = controllers.SelectMany(controller =>
    controller.Actions.Select(action =>
        new
        {
            Controller = controller,
            Action = action
        })
    )
    .ToDictionary(
        item => item.Controller.Name + "." + item.Action.Name,
        item => item.Action.HttpCache);

This would be for the case where you have your data set up like this:

var controllers = new[] {
    new Controller()
    {
        Name = "Test1",
        Actions = new Action[] {
            new Action { Name = "Action1", HttpCache = 300 },
            new Action { Name = "Action2", HttpCache = 200 },
            new Action { Name = "Action3", HttpCache = 400 },
        }
    },
    new Controller()
    {
        Name = "Test2",
        Actions = new Action[] {
            new Action { Name = "Action1", HttpCache = 300 },
            new Action { Name = "Action2", HttpCache = 200 },
            new Action { Name = "Action3", HttpCache = 400 },
        }
    },
};

Upvotes: 0

Related Questions