mardi 12 janvier 2021

Dynamic lambda for IEnumerable.Select

I need to break up a large table into a series of 2-column tables to dynamically create table rules for a configurator engine. This code demonstrates the problem:

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

namespace Spike
{
    class Program
    {
        static void Main(string[] args)
        {
            // The actual data I need to break down has ~20 properties of type string and decimal, over 18,000 rows
            var data = new List<MyData>()
            {
                new MyData("one", "two", 3m, "four"),
                new MyData("five", "six", 7m, "eight"),
                new MyData("nine", "ten", 11m, "twelve"),
                new MyData("thirteen", "fourteen", 15m, "sixteen"),
                new MyData("one", "five", 9m, "thirteen"),
                new MyData("two", "six", 10m, "fourteen"),
                new MyData("three", "seven", 11m, "fifteen"),
                new MyData("four", "eight", 12m, "sixteen")
            };

            // This shows the desired combinations of properties
            // The actual data will have ~230 combinations
            var properties = typeof(MyData).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            for (var i = 0; i < properties.Length - 1; i++)
            {
                for (var j = i + 1; j < properties.Length; j++)
                {
                    Console.WriteLine($"{properties[i].Name} <=> {properties[j].Name}");
                }
            }
            /* output:
                P1 <=> P2
                P1 <=> P3
                P1 <=> P4
                P2 <=> P3
                P2 <=> P4
                P3 <=> P4
            */

            // This shows how I want one combination to appear
            // The challenge seems to be the creation of a dynamic lambda in the Select method.
            var items = data.Select(x => new { x.P2, x.P3 }).Distinct().ToList();
            Console.WriteLine();
            items.ForEach(x => Console.WriteLine($"{x.P2}, {x.P3}"));
            /* output:
                two, 3
                six, 7
                ten, 11
                fourteen, 15
                five, 9
                six, 10
                seven, 11
                eight, 12
            */

            Console.ReadKey();
        }
    }

    public class MyData
    {
        public string P1 { get; set; }
        public string P2 { get; set; }
        public decimal P3 { get; set; }
        public string P4 { get; set; }

        public MyData(string p1, string p2, decimal p3, string p4)
        {
            P1 = p1;
            P2 = p2;
            P3 = p3;
            P4 = p4;
        }
    }
}

I've researched Linq, Reflection, and Expression Trees and can't seem to get past the hurdle of dynamically building this expression:

var items = data.Select(x => new { x.P2, x.P3 }).Distinct().ToList();

where x.P2 and x.P3 are dynamic.

This post seems to be headed in the right direction, but I'm not getting the result to work.

Suggestions? Thanks in advance!





Aucun commentaire:

Enregistrer un commentaire