Grupo C# por columna y forma datos jerárquicos con otras columnas

Estoy tratando de agrupar una columna y formar el resto de las columnas como niño, datos jerárquicos:

enter image description here

Estoy tratando de agrupar por Código y formar la relación padre e hijo de una lista plana, a continuación se encuentran los datos jerárquicos que estoy tratando de formar:

lista de fuentes:

 public class ItemAssignmentFlatList
 {
  public int Code { get; set; }
  public string Type { get; set; }
  public string Description { get; set; }
  public int ItemCode{ get; set; }
  public DateTime EffectiveDate{ get; set; }
  public string Area{ get; set; }
  public string TaxCode{ get; set; }
  public string LocationId { get; set; }
 }

Necesidad de convertir la lista plana arriba en abajo Lista de datos jerárquicos:

public class ItemInfo
{
    public int Code { get; set; }
    public string Type { get; set; }
    public string Description { get; set; }
    public List TaxPlan { get; set; }
}

public class TaxPlan 
{
    public int ItemCode{ get; set; }
    public DateTime EffectiveDate{ get; set; }
    public string Area{ get; set; }
    public string TaxCode{ get; set; }
    public string LocationId { get; set; }
}

Necesidad de lista jerárquica con lista de datos plana arriba con métodos de extensión C#.

Tengo bajo código, pero buscando código limpio para reducir el número de líneas:

var items= results.GroupBy(x => new { x.Code, x.Type });

List result = new List();

foreach (var group in items)
{
  var taxPlans = group.
                   Select(y => new TaxPlan
                   {
                     TaxArea = y.TaxArea,
                     ItemCode = y.ItemCode
                   });

  var itemInfo= new ItemInfo
                     {
                       Code = group.FirstOrDefault().Code,
                       Type = group.FirstOrDefault().Type,
                       Description = group.FirstOrDefault().Description,
                       TaxPlan = taxPlans.ToList()
                     };

   result.Add(itemInfo);
}

Pregunta hecha hace 3 años, 4 meses, 29 días - Por scriptsculptorbf10


4 Respuestas:

  • ¿Algo como esto?

    var input = new List(){
        new ItemAssignmentFlatList{
            Code = 1,
            Area = "a"
        },
        new ItemAssignmentFlatList{
            Code = 1,
            Area = "b"
        },
        new ItemAssignmentFlatList{
            Code = 2,
            Area = "c"
        }
    };
    
    input
        .GroupBy(
            x => x.Code,
            (int code, IEnumerable items) =>
            {
                var first = items.FirstOrDefault();
                
                var key = new ItemInfo
                {
                    Code = first.Code
                    //, ...
                };
    
                var plan = items.
                    Select(y => new TaxPlan
                    {
                        Area = y.Area
                        //, ...
                    });
    
                return new
                {
                    key = key,
                    items = plan
                };
            }
        ).Dump();
    

    Respondida el Dec 18, 2020 a las 21:25 - por cybermage

    Votos positivos: 0 | Votos negativos: 0

  • Cada vez que tienes una secuencia de objeto similar, y quieres hacer "Items con sus SubItems", basado en propiedades comunes en tu secuencia de origen, considera usar una de las sobrecargas de Enumerable. GroupBy

    Debido a que no sólo quiere "Grupos de elementos fuente" pero desea especificar su salida, considere utilizar la sobrecarga que tiene un resultado del parámetroSelector.

    • parámetro keySelector: qué deben tener todos los elementos de un grupo en común
    • Resultado del parámetroSelector: use la cosa común, y todos los elementos que tienen esta cosa común para hacer un elemento de salida.

    .

    IEnumerable flatItemAssignments = ...
    IEnumerable items = flatItemAssignments
    
        // make groups with same {Code, Type, Description}
        .GroupBy(flatItemAssignment => new {Code, Type, Description},
    
        // parameter resultSelector: take the common CodeTypeDescription,
        // and all flatItemAssignments that have this common value
        // to make one new ItemInfo
        (codeTypeDescription, flatItemAssignmentsWithThisCodeTypeDescription) => new ItemInfo
        {
            Code = codeTypeDescription.Code,
            Type = codeTypeDescription.Type,
            Description = codeTypeDescription.Description,
    
            TaxPlans = flatItemAssignmentsWithThisCodeTypeDescription
                .Select(flatItemAssignment => new TaxPlan
                {
                    ItemCode = flatItemAssignment.ItemCode,
                    EffectiveDate = flatItemAssignment.EffectiveDate,
                    Area = flatItemAssignment.Area,
                    ...
                })
                .ToList(),
        });
    

    Respondida el Dec 18, 2020 a las 21:30 - por scriptsphinx

    Votos positivos: 0 | Votos negativos: 0

  • Para simplificar tu código y reducir el número de líneas, puedes utilizar expresiones lambda y métodos de extensión de LINQ. Aquí te muestro una manera de hacerlo:

    csharp
    var results = // Tu lista de datos plana
    
    var result = results
        .GroupBy(x => new { x.Code, x.Type })
        .Select(group => new ItemInfo
        {
            Code = group.Key.Code,
            Type = group.Key.Type,
            Description = group.First().Description,
            TaxPlan = group.Select(y => new TaxPlan
            {
                ItemCode = y.ItemCode,
                EffectiveDate = y.EffectiveDate,
                Area = y.Area,
                TaxCode = y.TaxCode,
                LocationId = y.LocationId
            }).ToList()
        })
        .ToList();
    

    En este código, utilizamos GroupBy para agrupar por Code y Type, luego con Select creamos un nuevo ItemInfo con las propiedades correspondientes. Para TaxPlan, usamos otra proyección Select dentro de la lambda Select principal.

    Con este enfoque, puedes simplificar tu código y hacerlo más legible.

    Respondida el Dec 19, 2020 a las 21:29 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Versión mejorada y optimizada:

    csharp
    using System.Collections.Generic;
    using System.Linq;
    
    public static class ItemAssignmentExtensions
    {
        public static IEnumerable ToHierarchicalData(this IEnumerable flatList)
        {
            return flatList
                .GroupBy(x => new { x.Code, x.Type })
                .Select(g => new ItemInfo
                {
                    Code = g.Key.Code,
                    Type = g.Key.Type,
                    Description = g.FirstOrDefault()?.Description,
                    TaxPlan = g.Select(x => new TaxPlan
                    {
                        ItemCode = x.ItemCode,
                        EffectiveDate = x.EffectiveDate,
                        Area = x.Area,
                        TaxCode = x.TaxCode,
                        LocationId = x.LocationId
                    }).ToList()
                });
        }
    }
    

    Uso:

    csharp
    // Lista de datos planos de ItemAssignment
    var flatList = new List
    {
        // Datos de muestra...
    };
    
    // Conversión a datos jerárquicos de ItemInfo
    var hierarchicalData = flatList.ToHierarchicalData();
    

    Explicación:

    El método de extensión ToHierarchicalData toma una secuencia de objetos ItemAssignmentFlatList y la convierte en una secuencia de objetos ItemInfo jerárquicos. Utiliza la agrupación LINQ para agrupar los elementos planos por Code y Type. Para cada grupo, crea un objeto ItemInfo con el Code, Type y Description del primer elemento. También crea una lista de objetos TaxPlan a partir de los elementos del grupo, utilizando la proyección de propiedades. * El resultado es una secuencia de objetos ItemInfo jerárquicos, con una lista de objetos TaxPlan anidados para cada elemento.

    Respondida el Dec 19, 2020 a las 21:38 - por Gemini

    Votos positivos: 0 | Votos negativos: 0