How to combine two flat lists into one nested object

后端 未结 4 520
-上瘾入骨i
-上瘾入骨i 2021-01-25 12:25

I have three lists which contains three same properties in each collection. I want to combine a result into one collection. Ex classes structure is as below

publ         


        
相关标签:
4条回答
  • 2021-01-25 12:57

    There seems to be a number of questions here combined, I'll try to work through them:

    Data Models and Deserialization

    With respect to generating a single structure from your API response, I would recommend using the Newtonsoft.Json libraries, available on NuGet Json.NET. They will allow you to deserialize the response from your API, into a single object, which given the sample you provided, should contain a collection of each of your models, Order, PaymentDetail, CouponUsageDetail:

    public class APIResponceContainer
    {
        [JsonProperty("Orders")]
        public List<Order> Orders { get; set; }
        [JsonProperty("PaymentDetails")]
        public List<PaymentDetail> PaymentDetails { get; set; }
        [JsonProperty("CouponUsageDetails")]
        public List<CouponUsageDetail> CouponUsageDetails { get; set; }
    
        public APIResponceContainer()
        {
            Orders = new List<Order>();
            PaymentDetails = new List<PaymentDetail>();
            CouponUsageDetails = new List<CouponUsageDetail>();
        }
    }
    

    Be aware to add the required attributes to each of your models as so:

    public class Order
    {
        [JsonProperty("ProductId")]
        public int ProductId { get; set; }
        [JsonProperty("CustomerId")]
        public int CustomerId { get; set; }
        [JsonProperty("OrderId")]
        public int OrderId { get; set; }
    }
    

    Deserialization then happens from your JSON string, as such:

    StringReader stringReader = new StringReader(myJSONString);
    JsonSerializer js = JsonSerializer.Create();
    APIResponceContainer APIResponce = (APIResponceContainer)js.Deserialize(stringReader, typeof(APIResponceContainer));
    

    Queries

    As discussed in the comments, your data is unfortunately in terrible need of normalization. However, what I have inferred is that you would like to produce a flat structure, maintaining the "Few other Properties" and "key properties", for a combination of Order, PaymentDetail and CouponUsageDetail. You can use Linq for this, importantly I would recommend you choose yourself a "Primary Key". In other words, one property that can independently tie all the others together. In the example below, I have choose OrderID since it should be unique (?):

    var flatSequence =
                from order in APIResponce.Orders
                join coupon in APIResponce.CouponUsageDetails on order.OrderId equals coupon.OrderId
                join payment in APIResponce.PaymentDetails on order.OrderId equals payment.OrderId
                select new
                {
                    // Here extract all the properties you care about
                    OrderID = order.OrderId,
                    Customer = order.CustomerId,
                    Product = order.ProductId,
                    // All the "other Properties" ?
                    BankDetail = payment.PaymentOnlyProperty
                };
    

    Here I have extracted to var, however if you know the final flat structure you would like, of course determine a class of your own to receive the result.

    Please comment if there is any questions.

    0 讨论(0)
  • 2021-01-25 12:59

    What are you describing sounds like two standard multi-key LINQ group joins. They are quite efficient (LINQ to Objects implementation uses prepared fast hash based lookups), so no further optimizations are needed:

    var orderDetails = (
        from o in data.Orders
        join p in data.PaymentDetails
            on new { o.ProductId, o.CustomerId, o.OrderId }
            equals new { p.ProductId, p.CustomerId, p.OrderId }
            into orderPaymentDetails
        join c in data.CouponUsageDetails
            on new { o.ProductId, o.CustomerId, o.OrderId }
            equals new { c.ProductId, c.CustomerId, c.OrderId }
            into orderCouponUsageDetails
        select new OrderDetails
        {
            ProductId = o.ProductId,
            CustomerId = o.CustomerId,
            OrderId = o.OrderId,
            // Few other Properties of OrderDetail
            PaymentDetail = orderPaymentDetails.ToList(),
            CouponUsageDetail = orderCouponUsageDetails.ToList(),
        })
        .ToList();
    
    0 讨论(0)
  • 2021-01-25 13:22

    You can use inheritance.

    public class ResultCollection : Collection1
    {
        List<Collection2> Collection2s { get; set; }
        List<Collection3> Collection3s { get; set; }
    }
    

    and then

    var result = new ResultCollection {
        PropId1 = Collection1.PropId1,
        PropId2 = Collection1.PropId2,
        ...
        Collection2s = Collection2,
        Collection3s = Collection3
    }
    

    An automapper can be helpful here.
    https://docs.automapper.org/en/stable/

    0 讨论(0)
  • 2021-01-25 13:23

    I have solution, but i am not sure if it's ok for you. It depends on data format that you have on the begining.

    solution:

    class Program
    {
        static void Main(string[] args)
        {
            var collection1 = new Collection1() { PropId1 = 1, PropId2 = 2, PropId3 = 3 };
    
            var list2 = new List<Collection2>()
            {
                new Collection2
                {
                    PropId1 = 11,
                    PropId2 = 22,
                    PropId3 = 33
                },
                new Collection2
                {
                    PropId1 = 22,
                    PropId2 = 33,
                    PropId3 = 44
                }
            };
            var list3 = new List<Collection3>()
            {
                new Collection3
                {
                    PropId1 = 111,
                    PropId2 = 222,
                    PropId3 = 333
                },
                new Collection3
                {
                    PropId1 = 222,
                    PropId2 = 333,
                    PropId3 = 444
                }
            };
    
            var result = new ResultCollection(collection1, list2, list3);
            //or
            var result2 = new ResultCollection(collection1) //but in this case you have to change your constructor
            {
                Collection2s = list2,
                Collection3s = list3
            };
            Console.ReadLine();
        }
    }
    
    public class Collection1
    {
        public int? PropId1 { get; set; }
        public int? PropId2 { get; set; }
        public int? PropId3 { get; set; }
    }
    public class Collection2
    {
        public int? PropId1 { get; set; }
        public int? PropId2 { get; set; }
        public int? PropId3 { get; set; }
    }
    public class Collection3
    {
        public int? PropId1 { get; set; }
        public int? PropId2 { get; set; }
        public int? PropId3 { get; set; }
    }
    
    public class ResultCollection : Collection1
    {
        public ResultCollection() { }
    
        public ResultCollection(Collection1 collection, List<Collection2> list2, List<Collection3> list3)
        {
            foreach (PropertyInfo prop in collection.GetType().GetProperties())
            {
                PropertyInfo prop2 = collection.GetType().GetProperty(prop.Name);
                if (prop2.CanWrite)
                    prop2.SetValue(this, prop.GetValue(collection, null), null);
            }
            Collection2s = list2;
            Collection3s = list3;
        }
    
        public List<Collection2> Collection2s { get; set; }
    
        public List<Collection3> Collection3s { get; set; }
    }
    

    But can you give an example of input data?

    0 讨论(0)
提交回复
热议问题