2009-07-29 27 views
101

En ASP.NET C# que tienen una estructura:seleccionar varios campos de la Lista de LINQ

public struct Data 
{ 
    public int item1; 
    public int item2; 
    public int category_id; 
    public string category_name; 
} 

y tengo una lista de las personas. Quiero seleccionar category_id y category_name, ejecutando un DISTINCT y finalmente un ORDERBY en category_name.

Esto es lo que tengo ahora:

List<Data> listObject = getData(); 
string[] catNames = listObject 
        .Select(i=> i.category_name) 
        .Distinct() 
        .OrderByDescending(s => s) 
        .ToArray(); 

Obviamente, esto sólo se pone el nombre de la categoría. Mi pregunta es, ¿cómo obtengo múltiples campos y en qué estructura de datos voy a almacenar esto (no es string[])?

EDITAR

Usando una lista de estructuras no está escrito en piedra. Si sería aconsejable cambiar la estructura de datos de mi respaldo para facilitar las selecciones (escribiré muchas de ellas) entonces con mucho gusto recibiré recomendaciones.

+8

Si bien es sin relación con el lado de LINQ, * muy * le aconsejo que no use estructuras mutables o campos públicos. Personalmente, raramente creo estructuras, en primer lugar, pero las estructuras mutables solo están buscando problemas. –

+0

@Jon Skeet Gracias. Lo convertiré en una clase regular con miembros privados. – Chet

+1

@Jon Skeet ¿Por qué? – Midhat

Respuesta

175

Los tipos anónimos permiten seleccionar campos arbitrarios en las estructuras de datos que están fuertemente tipado más adelante en su código:

var cats = listObject 
    .Select(i => new { i.category_id, i.category_name }) 
    .Distinct() 
    .OrderByDescending(i => i.category_name) 
    .ToArray(); 

Dado que usted (al parecer) necesita almacenarlo para r su uso posterior, puede utilizar el operador GroupBy:

Data[] cats = listObject 
    .GroupBy(i => new { i.category_id, i.category_name }) 
    .OrderByDescending(g => g.Key.category_name) 
    .Select(g => g.First()) 
    .ToArray(); 
+0

Quiero usar distinct en 1 columna y recuperar varias columnas.SO ¿cómo puedo hacerlo? –

+1

Nunca pensé en 'Seleccionar' en un nuevo tipo. En mi caso, seleccioné un nuevo 'KeyValuePair'. – cjbarth

20

Se podría utilizar un tipo anónimo:

.Select(i => new { i.name, i.category_name }) 

El compilador generará el código para una clase con name y category_name propiedades y devuelve instancias de esa clase. También puede especificar manualmente nombres de propiedades:

i => new { Id = i.category_id, Name = i.category_name } 

Puede tener un número arbitrario de propiedades.

3
var result = listObject.Select(i => new{ i.category_name, i.category_id }) 

Este utiliza los tipos anónimos por lo que debe la palabra clave var, ya que el tipo resultante de la expresión no se conoce de antemano.

5

Esta es la tarea para la cual anonymous types son muy adecuados. Puede devolver objetos de un tipo que el compilador crea automáticamente, deducidos del uso.

La sintaxis es de esta forma:

new { Property1 = value1, Property2 = value2, ... } 

Para su caso, intente algo como lo siguiente:

var listObject = getData(); 
var catNames = listObject.Select(i => 
    new { CatName = i.category_name, Item1 = i.item1, Item2 = i.item2 }) 
    .Distinct().OrderByDescending(s => s).ToArray(); 
22
var selectedCategories = 
    from value in 
     (from data in listObject 
     orderby data.category_name descending 
     select new { ID = data.category_id, Name = data.category_name }) 
    group value by value.Name into g 
    select g.First(); 

foreach (var category in selectedCategories) Console.WriteLine(category); 

Editar: Hecho más LINQ-ey!

+0

Jaja, gracias, bueno, aprecio la ayuda. Aparentemente esta no era la pregunta más difícil en el mundo. – Chet

+0

@IRBMe Disculpe, pequeña pregunta. ¿Qué es exactamente 'valor'? –

3
(from i in list 
select new { i.category_id, i.category_name }) 
.Distinct() 
.OrderBy(i => i.category_name); 
2

Puede seleccionar múltiples campos usando linq Seleccione como se muestra arriba en varios ejemplos, esto retornará como un tipo anónimo. Si quieres evitar este tipo anónimo, aquí está el truco simple.

var items = listObject.Select(f => new List<int>() { f.Item1, f.Item2 }).SelectMany(item => item).Distinct(); 

creo que esto resuelve su problema

2

Se puede hacer un KeyValuePair, por lo que va a devolver un "IEnumerable<KeyValuePair<string, string>>"

Por lo tanto, será la siguiente:

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name)).Distinct(); 
Cuestiones relacionadas