c# - Diferencia entre Select y SelectMany


He estado buscando la diferencia entre Select y SelectMany pero no he podido encontrar una respuesta adecuada. Necesito aprender la diferencia cuando uso LINQ to SQL pero todo lo que he encontrado son ejemplos de matriz estándar.

¿Alguien puede proporcionar un ejemplo LINQ To SQL?


Answers



SelectMany aplana las consultas que devuelven listas de listas. Por ejemplo

public class PhoneNumber
{
    public string Number { get; set; }
}

public class Person
{
    public IEnumerable<PhoneNumber> PhoneNumbers { get; set; }
    public string Name { get; set; }
}

IEnumerable<Person> people = new List<Person>();

// Select gets a list of lists of phone numbers
IEnumerable<IEnumerable<PhoneNumber>> phoneLists = people.Select(p => p.PhoneNumbers);

// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);

// And to include data from the parent in the result: 
// pass an expression to the second parameter (resultSelector) in the overload:
var directory = people
   .SelectMany(p => p.PhoneNumbers,
               (parent, child) => new { parent.Name, child.Number });

Demostración en vivo en .NET Fiddle




Seleccionar muchos es como la operación de combinación cruzada en SQL donde toma el producto cruzado.
Por ejemplo, si tenemos

Set A={a,b,c}
Set B={x,y}

Seleccionar muchos se puede utilizar para obtener el siguiente conjunto

{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }

Tenga en cuenta que aquí tomamos todas las combinaciones posibles que se pueden hacer a partir de los elementos del conjunto A y el conjunto B.

Aquí hay un ejemplo de LINQ que puedes probar

  List<string> animals = new List<string>() { "cat", "dog", "donkey" };
  List<int> number = new List<int>() { 10, 20 };

  var mix=number.SelectMany(num => animals, (n, a) => new { n, a });

la mezcla tendrá los siguientes elementos en una estructura plana como

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}



var players = db.SoccerTeams.Where( c=> c.Country == "Spain")
.SelectMany( c => c.players);

foreach(var player in players) { Console.WriteLine( player.LastName); }

  1. Ronaldo
  2. Messi
  3. Fábregas
  4. Bala
  5. Casillas

...




SelectMany() permite colapsar una secuencia multidimensional de una manera que de otra manera requeriría un segundo Select() o loop.

Más detalles en esta publicación de blog .




Hay varias sobrecargas para SelectMany . Uno de ellos le permite mantener un rastro de cualquier relación entre padres e hijos al atravesar la jerarquía.

Ejemplo : supongamos que tiene la siguiente estructura: League -> Teams -> Player

Puede devolver fácilmente una colección plana de jugadores. Sin embargo, puede perder cualquier referencia al equipo del que el jugador es parte.

Afortunadamente hay una sobrecarga para tal fin:

var teamsAndTheirLeagues = 
         from helper in leagues.SelectMany
               ( l => l.Teams
                 , ( league, team ) => new { league, team } )
                      where helper.team.Players.Count > 2 
                           && helper.league.Teams.Count < 10
                           select new 
                                  { LeagueID = helper.league.ID
                                    , Team = helper.team 
                                   };

El ejemplo anterior está tomado del blog IK de Dan:

http://blogs.interknowlogy.com/2008/10/10/use-linqs-selectmany-method-to-flatten-collections/

Recomiendo encarecidamente que lo eche un vistazo.




Entiendo que SelectMany funcione como un atajo de unión.

Así que puedes:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);



Select es una proyección simple de uno a uno desde el elemento de origen hasta un elemento de resultado. Seleccionar- Muchos se usan cuando hay varias cláusulas de una expresión de consulta: cada elemento en la secuencia original se usa para generar una nueva secuencia.




Algunos SelectMany pueden no ser necesarios. Debajo de 2 consultas dan el mismo resultado.

Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)

Orders.Where(o=>o.Customer.Name=="Tom")

Para la relación de 1 a muchos,

  1. si se comienza desde "1", se necesita SelectMany, se aplanan los muchos.
  2. si comienza desde "Muchos", SelectMany no es necesario. ( Todavía se puede filtrar desde "1" , también es más simple que la consulta de unión estándar por debajo)
from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o



Sin llegar a ser demasiado técnico: base de datos con muchas organizaciones, cada una con muchos usuarios:

var orgId = "123456789";

var userList1 = db.Organizations
                   .Where(a => a.OrganizationId == orgId)
                   .SelectMany(a => a.Users)
                   .ToList();

var userList2 = db.Users
                   .Where(a => a.OrganizationId == orgId)
                   .ToList();

ambos devuelven la misma lista UserUser para la organización seleccionada.

Los primeros "proyectos" de la Organización a los usuarios, el segundo consulta la tabla Usuarios directamente.




Solo para una vista alternativa que pueda ayudar a algunos programadores funcionales:

  • Select es map
  • SelectMany es bind (o flatMap para su gente de Scala / Kotlin)



Es más claro cuando la consulta devuelve una cadena:

Por ejemplo, si la lista 'Archivos' contiene el nombre de archivo 'afile.txt'

'Seleccionar' devuelve la cadena:

Files.Select(f=>f.Filename) 

[0]: "afile.txt"

'SelectMany' aplana la cadena:

Files.SelectMany(f=>f.Filename)

[0]: 97  'a'
[1]: 102 'f'
[2]: 105 'i'
[3]: 108 'l'
[4]: 101 'e'
[5]: 46  '.'
[6]: 116 't'
[7]: 120 'x'
[8]: 116 't'



Es la mejor manera de entender lo que pienso.

            var query =
            Enumerable
                .Range(1, 10)
                .SelectMany(ints => Enumerable.Range(1, 10), (a, b) => $"{a} * {b} = {a * b}")
                .ToArray();

        Console.WriteLine(string.Join(Environment.NewLine, query));

        Console.Read();

Ejemplo de Tabla de multiplicación.