2010-05-14 12 views
5

Esta pregunta es similar a LINQ group one type of item pero se maneja de una manera más genérica.LINQ - tipos de clases específicos de grupo

Tengo una lista que tiene varias clases derivadas. Puede que tenga algo como esto:

List<BaseClass> list = new List<BaseClass>() { 
    new Class1(1), 
    new Class2(1), 
    new Class1(2), 
    new Class3(1), 
    new Class2(2), 
    new Class4(1), 
    new Class3(2) 
}; 

Estoy tratando de utilizar LINQ a semi-Ordenar la lista por lo que el orden natural se mantiene con excepción de ciertas clases que tienen base.GroupThisType == true. Todas las clases con GroupThisType deben agruparse juntas en el lugar donde se produce la primera clase del mismo tipo. Esto es lo que la salida debería ser como:

List<BaseClass> list = new List<BaseClass>() { 
    new Class1(1), 
    new Class1(2), 
    new Class2(1), 
    new Class3(1), 
    new Class3(2) 
    new Class2(2), 
    new Class4(1), 
}; 

Editar: Vaya, se olvidó de decir que este resultado está asumiendo (Clase 1 y Class3) .GroupThisType == true

+0

1 Incluso reto más bonito – SLaks

+0

@SLaks: Sí, lo único que pensaba es GroupThisType se duplicaría y en teoría podría ser diferente para las instancias de la misma clase. Crearía una lista groupTheseTypes, pero no sé los tipos de antemano (sistema tipo plugin). Una variable estática probablemente tenga más sentido. No cambia tu respuesta. –

+0

... excepto si lo quiero en la clase base, no puedo hacerlo estático, de lo contrario, solo tengo una instancia de esa variable. Oh, bueno ... –

Respuesta

1

De esta manera:

list = list.Select((o, i) => new { Index = i * 10000, Value = o }) 
      .GroupBy(q => q.GetType()) 
      .SelectMany(g => { 
       if (g.First().GroupThisType) 
        return g.Select((q, i) => 
         new { Index = g.First().Index + i, Value = q.Value } 
        ); 
       else 
        return g; 
      }) 
      .OrderBy(q => q.Index) 
      .Select(q => q.Value) 
      .ToList(); 

El i * 10000 permite hasta 10.000 artículos de un grupo para ser insertados entre dos elementos.

Puede reemplazar g.First().GroupThisType con typesToGroup.Contains(g.Key).

+0

Estoy empezando a pensar que un enfoque más tradicional sería más fácil de entender :) Además, al hacer i * 10000, estás limitando la cantidad total de elementos que puede haber. Supongo que es un int, por lo tanto 2147483647/10000 = 214748 max items. Todavía CAMINO sobre lo que alguna vez tendría. –

+0

'i' es un' int', pero puede convertirlo en 'long'. – SLaks

0

El método OrdenarPor LINQ puede aceptar una Interfaz genérica IComparer. Puede usar esto para implementar su algoritmo de clasificación personalizado. No sé si el orden predeterminado puede manejar lo que estás tratando de hacer (dependerá de todas las reglas que necesites implementar). Supongo que sus clases en realidad no se denominan Class1, Class2 con el orden en el nombre del tipo?

HTH.

+1

Quiere preservar el orden original, pero mueve todos los elementos de ciertos tipos a la posición de la primera aparición. No es posible hacer eso con un 'IComparer'. – SLaks

1

Aquí hay una solución que usa dos pases: en el primero construyo un diccionario de todos los que deberían agruparse. En el segundo uso SelectMany para reunir los elementos que no se cotejan con las secuencias intercaladas para el primero de los elementos que se cotejan.

// Build a dictionary of the items that group 
var onesToGroup = list.Where(x => x.GroupThisClass) 
          .GroupBy(x => x.GetType()) 
          .ToDictionary(x => x.Key, x => x.AsEnumerable()); 

var results = list.SelectMany(x => x.GroupThisClass ? 
          (onesToGroup[x.GetType()].First() == x ? onesToGroup[x.GetType()] : (new BaseClass[]{})) 
               : (new []{x})); 
+0

Pero lo hará, no estoy iterando sobre el diccionario, estoy iterando sobre la lista original y usando el diccionario solo para encontrar el grupo relevante. –

+0

Sí, tienes razón. Entendí mal. – SLaks

+0

Sin embargo, confía en que GroupBy esté en orden ... lo que afortunadamente MSDN confirma es el caso. –

Cuestiones relacionadas