Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

162
Vistas
C# reorganizar lista por patrón

Tengo una List<TimeAndCode> de objetos. Cada objeto contiene un Code y un valor de TimeSpan .

 public struct TimeAndCode { public TimeSpan Time { get; set; } public string Code { get; set; } }

Los códigos que aparecen están predefinidos como "CO" , "GO" y "BT" .

Cuando la propiedad Time alcanza el mismo valor, el orden de la lista debe tener un formato determinado. por ejemplo (representación JSON para legibilidad)

 [ {"Time" : "08:00:00", "Code" : "CO" }, {"Time" : "09:00:00", "Code" : "GO" }, {"Time" : "09:30:00", "Code" : "CO" }, {"Time" : "09:30:00", "Code" : "GO" }, {"Time" : "09:30:00", "Code" : "CO" }, {"Time" : "09:30:00", "Code" : "GO" }, {"Time" : "09:30:00", "Code" : "BT" }, {"Time" : "12:30:00", "Code" : "CO" }, {"Time" : "12:30:00", "Code" : "GO" }, {"Time" : "13:30:00", "Code" : "CO" }, {"Time" : "13:30:00", "Code" : "GO" }, {"Time" : "13:30:00", "Code" : "BT" }, {"Time" : "13:30:00", "Code" : "CO" }, {"Time" : "13:30:00", "Code" : "GO" } ]

Entonces, el patrón es CO -> GO o GO -> BT o CO -> GO -> BT -> CO -> GO .

Puede haber una buena solución anterior if else , pero estoy buscando una solución LINQ agradable y fácil de usar. (por ejemplo list.OrderBy( x => x.Time ).RearrangeBy( x => x.Code, pattern ); )

EDITAR

El pedido personalizado solo debe realizarse cuando los códigos se encuentran en la misma franja horaria.

El patrón más fácil es:

 CO -> GO -> CO -> GO -> CO -> GO

Pero también existe la posibilidad de que un BT pueda estar presente:

 CO -> GO -> BT -> CO -> GO -> BT -> CO -> GO -> BT -> CO

Pero también existe la posibilidad de que solo haya un BT:

 CO -> GO -> BT -> GO -> GO -> CO -> GO -> CO -> GO CO -> GO -> CO -> GO -> BT -> CO -> GO -> CO -> GO CO -> GO -> CO -> GO -> CO -> GO -> BT -> CO -> GO CO -> GO -> BT -> CO -> GO -> CO -> GO -> BT -> CO -> GO

Entonces, el patrón principal es CO -> GO -> BT .

EDITAR 2 Resuelto

Creé un método de extensión. Puede ser que este código sea útil para alguien. (margen de mejora)

 public static IEnumerable<TSource> RearrangeByPattern<TSource, TKey>(this IEnumerable<TSource> list, Func<TSource, TKey> keySelector, IEnumerable<TKey> pattern) { var groups = list.GroupBy(keySelector).OrderBy(x => pattern.IndexOf(x.Key)); var maxOccurences = groups.Select(x => x.Count()).Max(); var result = new List<TSource>(); for (var i = 0; i < maxOccurences; i++) { foreach (var group in groups) { if (group.Count() > i) { result.Add(group.ElementAt(i)); } } } return result; }

Ahora puedo usarlo así:

 var list = new List<TimeAndCode>(); ... // add values var ordered = list.OrderBy(x => x.Date).RearrangeByPattern( x => x.Code, new string[] { "CO", "GO", "BT" });
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Aquí hay una sugerencia donde TimeAndCode.Code es una enum en lugar de una string .

Siempre ordenará las entradas con intervalos de tiempo idénticos en un patrón repetido de CO , GO , BT ; lo que significa que si, por ejemplo, cinco entradas con intervalos de tiempo idénticos tienen la siguiente selección de Code : 2 x CO , 1 x BT , 2 x GO , siempre las ordenará como CO , GO , BT , CO , GO (a diferencia de CO , GO , CO , GO , BT ).

Logro esto generando una propiedad OrderBy basada en el intervalo de tiempo, un índice (generado dentro de un grupo anidado) y el valor del Code numérico para cada entrada.

Usando los siguientes tipos:

 public struct TimeAndCode { public TimeSpan Time { get; set; } public Code Code { get; set; } } public enum Code { Undefined, CO, GO, BT }

podemos escribir la siguiente expresión:

 List<TimeAndCode> result = list .GroupBy(entry => entry.Code) .SelectMany(gr => gr .GroupBy(entry => entry.Time) .SelectMany(gr => gr.Select((entry, index) => ( OrderBy: entry.Time.ToString() + index + (int)entry.Code, TimeAndCode: entry)))) .OrderBy(entry => entry.OrderBy) .Select(entry => entry.TimeAndCode) .ToList();

donde list es List<TimeAndCode> .


Usando la entrada de ejemplo de la siguiente manera:

 List<TimeAndCode> list = new List<TimeAndCode> { new TimeAndCode { Time = new TimeSpan(09, 00, 00), Code = Code.GO }, new TimeAndCode { Time = new TimeSpan(13, 30, 00), Code = Code.BT }, new TimeAndCode { Time = new TimeSpan(09, 30, 00), Code = Code.GO }, new TimeAndCode { Time = new TimeSpan(09, 30, 00), Code = Code.GO }, new TimeAndCode { Time = new TimeSpan(13, 30, 00), Code = Code.GO }, new TimeAndCode { Time = new TimeSpan(08, 00, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(09, 30, 00), Code = Code.BT }, new TimeAndCode { Time = new TimeSpan(12, 30, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(09, 30, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(12, 30, 00), Code = Code.GO }, new TimeAndCode { Time = new TimeSpan(13, 30, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(13, 30, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(09, 30, 00), Code = Code.CO }, new TimeAndCode { Time = new TimeSpan(13, 30, 00), Code = Code.GO }, };

, después de aplicar la expresión Linq, podemos imprimir el resultado

 foreach (var entry in result) { Console.WriteLine("Time: " + entry.Time + " Code: " + entry.Code); }

y obtener el siguiente resultado:

 Time: 08:00:00 Code: CO Time: 09:00:00 Code: GO Time: 09:30:00 Code: CO Time: 09:30:00 Code: GO Time: 09:30:00 Code: BT Time: 09:30:00 Code: CO Time: 09:30:00 Code: GO Time: 12:30:00 Code: CO Time: 12:30:00 Code: GO Time: 13:30:00 Code: CO Time: 13:30:00 Code: GO Time: 13:30:00 Code: BT Time: 13:30:00 Code: CO Time: 13:30:00 Code: GO
over 4 years ago · Santiago Trujillo Denunciar

0

Es una variación de Astrid:

 var r = list.GroupBy(tc => tc) .SelectMany(g => g.Select((tc, i) => (tc, i))) .OrderBy(t => (t.tc.Time, ti, t.tc.Code)) .Select(t => t.tc);

Con la siguiente configuración precursora:

 public record TimeAndCode(TimeSpan Time, Code Code); public enum Code { CO, GO, BT } ... var list = new List<TimeAndCode> { new (TimeSpan.FromHours(8), Code.CO), new (TimeSpan.FromHours(9), Code.GO), new (TimeSpan.FromHours(9.5), Code.CO), new (TimeSpan.FromHours(9.5), Code.GO), new (TimeSpan.FromHours(9.5), Code.GO), new (TimeSpan.FromHours(9.5), Code.CO), new (TimeSpan.FromHours(9.5), Code.BT), new (TimeSpan.FromHours(12.5), Code.CO), new (TimeSpan.FromHours(12.5), Code.GO), new (TimeSpan.FromHours(13.5), Code.CO), new (TimeSpan.FromHours(13.5), Code.BT), new (TimeSpan.FromHours(13.5), Code.GO), new (TimeSpan.FromHours(13.5), Code.CO), new (TimeSpan.FromHours(13.5), Code.GO), };

TimeAndCode es un registro, lo que significa que adquiere algunas propiedades útiles para ordenar y comparar. Se puede agrupar simplemente porque es automáticamente igual a otro TimeAndCode con los mismos datos

La agrupación por tiempo y código da como resultado una lista de listas; los dos 9:30 CO s van en una lista. Pasar esto a Select((tc,i) significa que i es 0 para el primero y 1 para el segundo, etc. Todo lo que hacemos con esto es promocionarlo a una tupla de tc e i porque los necesitaremos más tarde , y seleccionamos Muchos para deshacer el GroupBy que nos permitía contar el mismo Tiempo/Código

Ordenamos por otra tupla; las tuplas se ordenan por sus valores en orden, así que para ordenar por 3 cosas a, b y c, podemos ordenar por una tupla de (a, b, c)

Y todo lo que queda por hacer al final es seleccionar el tc back para hacer una lista de TimeAndCode, ordenada algo como lo que desea

Al igual que Astrid, tampoco pone el BT al final de las 9:30, sino que va en el medio, como lo hace el de las 13:30. Pero no has proporcionado una explicación de por qué el BT de las 9:30 está al final. ..

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda