3

I have a list of items. I want to loop through the list and merge all members that have the same CN8, MSConsDestCode and countryOfOriginCode.

Also netMass should be a subtotal of netMass properties of merged items.

public class Item
    {
        public int CN8 { get; internal set; }
        public string goodsDescription { get; internal set; }
        public string MSConsDestCode { get; internal set; }
        public string countryOfOriginCode { get; internal set; }
        public decimal netMass { get; internal set; }
    }

From this:

var data = new List<Item>
{
    new Item {CN8 = 123456789, goodsDescription = "blah0", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  },
    new Item {CN8 = 123456789, goodsDescription = "blah1", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  }
    new Item {CN8 = 123456789, goodsDescription = "blah2", MSConsDestCode = "GB", countryOfOriginCode = "IN", netMass = 1  }
},

I'm looking for a result like this: (first two items merged, since they have the same CN8, MSConsDestCode and countryofOriginCode, last item is the same as in previous list)/

{CN8 = 123456789, goodsDescription = "blah0", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 2  }
{CN8 = 123456789, goodsDescription = "blah2", MSConsDestCode = "GB", countryOfOriginCode = "IN", netMass = 1  }

Note: goodsDescription can be random name from any element that was merged.

I have a feeling I should try to use LINQ for this, but since I'm not really familiar with it, I'm asking you guys to guide me to a right direction.

  • Second result is basically third element in primary list, since there are no other members with the same required properties. As you can see first and second items were merged into one, since all their required properties match (cn8, MSConsDestCode and countryOfOriginCode) and their netMass was added up. – Julius Sabaliauskas Aug 13 '19 at 13:49
  • What type is `CN8`; also the code above doesn't compile? – Trevor Aug 13 '19 at 13:52
  • I'm not expecting any work done, I'm just asking to point me into right direction since I have absolutely zero experience with LINQ. Note, it might not be a LINQ solution, I'm just looking for methods to do it. – Julius Sabaliauskas Aug 13 '19 at 13:54
  • Çöđěxěŕ, it's "pseudo" code, I just copied some of my item properties. CN8 is basically an integer. – Julius Sabaliauskas Aug 13 '19 at 13:56
  • 2
    Use Linq: `GroupBy` then `Select`. – Sani Huttunen Aug 13 '19 at 13:57
  • 1
    `data.GroupBy(x => new {x.CN8, x.MSConsDestCode, x.countryOfOriginCode}).Select(x => new Item { CN8 = x.Key.CN8, goodsDescription = x.First().goodsDescription, MSConsDestCode = x.Key.MSConsDestCode, countryOfOriginCode = x.Key.countryOfOriginCode, netMass = x.Sum(v => v.netMass)});` – Sani Huttunen Aug 13 '19 at 13:59
  • Thank you very much Sani! Write an answer, I'll mark it – Julius Sabaliauskas Aug 13 '19 at 14:00
  • @SaniSinghHuttunen is linq just your preference or is there benefits to using it over something else? – Trevor Aug 13 '19 at 14:00
  • @Çöđěxěŕ: Well... I prefer Linq since it makes the code short and easy to understand and you don't need to write any loops (which might in some cases be cumbersome to follow/understand if the datastructure is complicated). These types of Linq-queries all look about the same regardless of the datastructure. – Sani Huttunen Aug 13 '19 at 14:05
  • Possible duplicate of [Using Linq to group a list of objects into a new grouped list of list of objects](https://stackoverflow.com/questions/2697253/using-linq-to-group-a-list-of-objects-into-a-new-grouped-list-of-list-of-objects) – Heretic Monkey Aug 13 '19 at 15:57

2 Answers2

-1

You can indeed use Linq to achieve this:

var data = new List<Item>
{
  new Item {CN8 = 123456789, goodsDescription = "blah0", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  },
  new Item {CN8 = 123456789, goodsDescription = "blah1", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  },
  new Item {CN8 = 123456789, goodsDescription = "blah2", MSConsDestCode = "GB", countryOfOriginCode = "IN", netMass = 1  }
};

var combined = data.GroupBy(x => new {x.CN8, x.MSConsDestCode, x.countryOfOriginCode})
                   .Select(x => new Item
                     {
                       CN8 = x.Key.CN8,
                       goodsDescription = x.First().goodsDescription,
                       MSConsDestCode = x.Key.MSConsDestCode,
                       countryOfOriginCode = x.Key.countryOfOriginCode,
                       netMass = x.Sum(v => v.netMass)
                     });
Sani Huttunen
  • 23,620
  • 6
  • 72
  • 79
-2

You want to group by then select:

using System;
using System.Collections.Generic;
using System.Linq;

namespace so
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = new List<Item>
            {
                new Item {CN8 = 123456789, goodsDescription = "blah0", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  },
                new Item {CN8 = 123456789, goodsDescription = "blah1", MSConsDestCode = "DE", countryOfOriginCode = "CN", netMass = 1  },
                new Item {CN8 = 123456789, goodsDescription = "blah2", MSConsDestCode = "GB", countryOfOriginCode = "IN", netMass = 1  }
            };

            // Here is your query
            var groupedData = data.GroupBy(di => new {di.CN8, di.MSConsDestCode, di.countryOfOriginCode}).Select(group => new Item{ netMass = group.Sum(gi => gi.netMass),goodsDescription = group.First().goodsDescription, CN8=group.Key.CN8, MSConsDestCode=group.Key.MSConsDestCode, countryOfOriginCode=group.Key.countryOfOriginCode} );
        }
    }

    public class Item
    {
        public int CN8 { get; internal set; }
        public string goodsDescription { get; internal set; }
        public string MSConsDestCode { get; internal set; }
        public string countryOfOriginCode { get; internal set; }
        public decimal netMass { get; internal set; }
    }
}

Note that here I'm picking the first group description but given that you stated in you original question a "random" element I thought picking the first is a better idea.

Dave3of5
  • 688
  • 5
  • 23