broke
broke

Reputation: 8302

Need help using Linq to transform a list into a different list

Lets say I have a list that contains 1 record:

[
  {
    "AccountNumber": 1234,
    "eDocConfirms": true,
    "eDocStatements": true,
    "eDocTaxforms": false
  }
]

This list is a strongly typed object with these properties:

        public int AccountNumber { get; set; }
        public bool? eDocConfirms { get; set; }
        public bool? eDocStatements { get; set; }
        public bool? eDocTaxforms { get; set; }

Using LINQ, I'd like to turn it into a list that looks like this:

[
  {
    "AccountNumber": 1234,
    "EDocumentTypeName ": "Confirms"
  },
  {
    "AccountNumber": 1234,
    "EDocumentTypeName": "Statements"
  }
]

This new list will a list of a different type:

public class DeliveryPreference
    {
        public int AccountNumber { get; set; }
        public string EDocumentTypeName { get; set; }
    }

Note that Taxforms was not included in the new list because it was set to false in the first list.

I know I could easily do this with some loops, but I would prefer using LINQ.

I understand that Stack Overflow prefers that I show what I have tried, but I am having trouble wrapping my brain around this.

Upvotes: 2

Views: 67

Answers (2)

Štefan Bartoš
Štefan Bartoš

Reputation: 404

This is very ugly code, but it works. It should be easy to comprehend. Reflection can be extracted to a new function.

using System;
using System.Linq;

public class Program
{
    public class Account {
      public int AccountNumber { get; set; }
        public bool? eDocConfirms { get; set; }
        public bool? eDocStatements { get; set; }
        public bool? eDocTaxforms { get; set; }
    }

    public class DeliveryPreference
    {
        public int AccountNumber { get; set; }
        public string EDocumentTypeName { get; set; }
    }

    public static void Main()
    {
        var acc = new Account {
            AccountNumber = 10,
            eDocConfirms = true,
            eDocStatements = false,
            eDocTaxforms = true
        };

        var transformed = acc.GetType()
            .GetProperties()
            .Where(p => p.PropertyType == typeof(bool?) 
                   && ((bool?)p.GetValue(acc)).HasValue
                  && ((bool?)p.GetValue(acc)).Value)
            .Select(p => new DeliveryPreference {
                AccountNumber = acc.AccountNumber,
                EDocumentTypeName = p.Name.Substring(4)
            });

        foreach (var t in transformed) {
            Console.WriteLine(t.AccountNumber);
            Console.WriteLine(t.EDocumentTypeName);
        }
    }
}

Upvotes: 0

Viktor Arsanov
Viktor Arsanov

Reputation: 1613

For this case I would use additional function

public static IEnumerable<string> GetTrueProperties(Data t)
{
    if (t.eDocConfirms == true) yield return "Confirms";
    if (t.eDocStatements == true) yield return "Statements";
    if (t.eDocTaxForms == true) yield return "Tax";
}

simply because it is an object and not a dictionary; else you could dynamically select properties which are true(or you could use reflection, but I think it would be too much here, since you have strongly typed object).

then it would look like

var list = new List<Data> {
new Data
{
    AccountNumber = 1,
    eDocConfirms = true,
    eDocStatements = true,
    eDocTaxForms = false
}
};
list.SelectMany(item => GetTrueProperties(item).Select(p => new DeliveryPreference
{
    AccountNumber = item.AccountNumber,
    EDocumentTypeName = p
}));

Upvotes: 5

Related Questions