Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Private
  • Views: 48
  • Last Modified:

Linq: How to perform GroupBy when working with 3 or more columns

I start off with the following list

    List items = new List();

    items.add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 2, ModelName =   "98 Regency" });

    items.add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 3, ModelName = "88 Delta" });

    items.add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 4, ModelName = "Alero" });

    items.add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 5, ModelName = "442" });

    items.add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 11, ModelName = "Skylark" });

    items.add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 13, ModelName = "Electra 225" });

    items.add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 14, ModelName = "Regal" });

    items.add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 16, ModelName = "Enclave" });

But would like it converted to the following format:

    List newList = new List();

    items.add(new VehicleWithModelList { MakeID = 1, MakeName = "Oldsmobile", new List<Model> () { This list would contain the 4 oldsmobile models from above}});

    items.add(new VehicleWithModelList { MakeID = 2, MakeName = "Buick", new List<Model> () { This list would contain the 4 buick models from above}});

I have the following linq to object query but I keep getting syntax errors stating it expects a semicolon before the last close parenthesis.

    var newList = items.GroupBy(x => new {x.MakeID, x.ModelID, x.MakeName, x.ModelName}, (key, group) => new { MakeID = key.MakeID, MakeName = key.MakeName, ModelList = group.Select(z => new Model { ModelID = z.ModelID, ModelName = z.ModelName })).Cast< VehicleWithModelList >();

What would be the correct way to accomplish this?
0
rawcoder
Asked:
rawcoder
  • 4
  • 2
1 Solution
 
Jens FiedererCommented:
Do you have a custom List type?  I'd expect List<Vehicle> here...
0
 
Jens FiedererCommented:
Any way, I'd do it like this:

            List<Vehicle> olds = new List<Vehicle>();
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 2, ModelName = "98 Regency" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 3, ModelName = "88 Delta" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 4, ModelName = "Alero" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 5, ModelName = "442" });

            List<Vehicle> buicks = new List<Vehicle>();
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 11, ModelName = "Skylark" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 13, ModelName = "Electra 225" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 14, ModelName = "Regal" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 16, ModelName = "Enclave" });

            List<Vehicle> all = olds.Concat(buicks).ToList();

            List<VehicleWithModelList> byHand = new List<VehicleWithModelList>();
            byHand.Add(new VehicleWithModelList { MakeID = 1, MakeName = "Oldsmobile", ModelList = olds });
            byHand.Add(new VehicleWithModelList { MakeID = 2, MakeName = "Buick", ModelList = buicks });

            IEnumerable<VehicleWithModelList> byGrouping = from x in all group x by x.MakeID into g
                    select new VehicleWithModelList { MakeID = g.Key, MakeName = g.First().MakeName, ModelList = g.ToList()};

Open in new window

0
 
Jens FiedererCommented:
Note the byHand is just putting the list together manually, byGrouping uses the LINQ group construction.  This requires MakeID and MakeName to be in lockstep, since it just uses the first MakeName found for the group...true in your example data.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Fernando SotoCommented:
Hi jensfiederer;

See if this fits your needs.

// Class level variable with original list
private List<Vehicle> items = new List<Vehicle>();

// Created original list of data
items.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 2, ModelName = "98 Regency" });
items.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 3, ModelName = "88 Delta" });
items.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 4, ModelName = "Alero" });
items.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 5, ModelName = "442" });
items.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 11, ModelName = "Skylark" });
items.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 13, ModelName = "Electra 225" });
items.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 14, ModelName = "Regal" });
items.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 16, ModelName = "Enclave" });

// Using Linq to Object to covert to a new format
var newList = from v in items
              group v by new {v.MakeID, v.MakeName}
              into vehicleGroup
              select new VehicleWithModelList()
              {
                  MakeID = vehicleGroup.Key.MakeID,
                  MakeName = vehicleGroup.Key.MakeName,
                  VehicleList = vehicleGroup.ToList()
              };
                         


// Class object used in original list
public class Vehicle
{
    public int MakeID { get; set; }
    public string MakeName { get; set; }
    public int ModelID { get; set; }
    public string ModelName { get; set; }
}
// Class object used to covert from old to new format
public class VehicleWithModelList
{
    private List<Vehicle> _vehicleList = new List<Vehicle>();

    public int MakeID { get; set; }
    public string MakeName { get; set; }
    public List<Vehicle> VehicleList
    {
        get { return _vehicleList; }
        set { _vehicleList = value; }
    } 
}                                     

Open in new window

0
 
Jens FiedererCommented:
Yup, was just about to post this as a suggested improvement on my first try (same idea):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace linqgroup {
    class Program {
        static void Main(string[] args) {
            List<Vehicle> olds = new List<Vehicle>();
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 2, ModelName = "98 Regency" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsmobile", ModelID = 3, ModelName = "88 Delta" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsie", ModelID = 4, ModelName = "Alero" });
            olds.Add(new Vehicle { MakeID = 1, MakeName = "Oldsie", ModelID = 5, ModelName = "442" });

            List<Vehicle> buicks = new List<Vehicle>();
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 11, ModelName = "Skylark" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 13, ModelName = "Electra 225" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 14, ModelName = "Regal" });
            buicks.Add(new Vehicle { MakeID = 2, MakeName = "Buick", ModelID = 16, ModelName = "Enclave" });

            List<Vehicle> all = olds.Concat(buicks).ToList();

            List<VehicleWithModelList> byHand = new List<VehicleWithModelList>();
            byHand.Add(new VehicleWithModelList { MakeID = 1, MakeName = "Oldsmobile", ModelList = olds });
            byHand.Add(new VehicleWithModelList { MakeID = 2, MakeName = "Buick", ModelList = buicks });

            IEnumerable<VehicleWithModelList> byGrouping = from x in all group x by x.MakeID into g
                    select new VehicleWithModelList { MakeID = g.Key, MakeName = g.First().MakeName, ModelList = g.ToList()};
            foreach (var x in byGrouping) {
                Console.WriteLine("{0}-{1}-{2}", x.MakeID, x.MakeName, x.ModelList.Count());
            }

            IEnumerable<VehicleWithModelList> by2Grouping = from x in all
                                                            group x by new KeyValuePair<int, string>(x.MakeID, x.MakeName)into g
                                                            select new VehicleWithModelList { MakeID = g.Key.Key, MakeName = g.Key.Value, ModelList = g.ToList() };
            foreach (var x in by2Grouping) {
                Console.WriteLine("{0}-{1}-{2}", x.MakeID, x.MakeName, x.ModelList.Count());
            }
        }


    }
    public class Vehicle {
        public int MakeID { get; set; }
        public string MakeName { get; set; }
        public int ModelID { get; set; }
        public string ModelName { get; set; }
    }

    public class VehicleWithModelList {
        public int MakeID { get; set; }
        public string MakeName { get; set; }
        private List<Vehicle> modelList = null;
        public IEnumerable<Vehicle> ModelList {
            get { return modelList; }
            set { modelList = value.ToList(); }
        }
    }
}

Open in new window

0
 
Fernando SotoCommented:
Sorry my original post was to be directed to the question author rawcoder.
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now