c# - seleccionar - Diferencia entre Select y SelectMany
seleccionar elementos de una lista c# (13)
Algunos SelectMany pueden no ser necesarios. A continuación 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 1-to-Many,
- si se inicia desde "1", se necesita SelectMany, se aplana la cantidad de unidades.
- Si comienza desde "Muchos", SelectMany no es necesario. ( todavía se puede filtrar desde "1" , esto también es más simple que la consulta de unión estándar)
from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o
He estado buscando la diferencia entre Select
y SelectMany
pero no he podido encontrar una respuesta adecuada. Necesito aprender la diferencia al usar LINQ To SQL, pero todo lo que he encontrado son ejemplos de matrices estándar.
¿Puede alguien proporcionar un ejemplo de LINQ To SQL?
Entiendo que SelectMany funciona como un acceso directo de combinación.
Así que puedes:
var orders = customers
.Where(c => c.CustomerName == "Acme")
.SelectMany(c => c.Orders);
Es la mejor manera de entender, creo.
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 multiplicar.
Es más claro cuando la consulta devuelve una cadena (una matriz de caracteres):
Por ejemplo, si la lista ''Frutas'' contiene ''manzana''
''Select'' devuelve la cadena:
Fruits.Select(s=>s)
[0]: "apple"
''SelectMany'' aplana la cadena:
Fruits.SelectMany(s=>s)
[0]: 97 ''a''
[1]: 112 ''p''
[2]: 112 ''p''
[3]: 108 ''l''
[4]: 101 ''e''
Hay varias sobrecargas a SelectMany
. Uno de ellos le permite hacer un seguimiento de cualquier relación entre padres e hijos mientras atraviesa la jerarquía.
Ejemplo : supongamos que tiene la siguiente estructura: League -> Teams -> Player
.
Puedes devolver fácilmente una colección plana de jugadores. Sin embargo, puede perder cualquier referencia al equipo del que forma parte el jugador.
Afortunadamente hay una sobrecarga para tal propósito:
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 de Dan IK . Te recomiendo que le eches un vistazo.
Seleccionar es una simple proyección uno a uno desde el elemento fuente a un elemento de resultado. Seleccionar: muchos se usan cuando hay varias cláusulas de en una expresión de consulta: cada elemento de la secuencia original se usa para generar una nueva secuencia.
Seleccionar muchos es como una operación de unió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 estructura plana como
{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
Sin 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 de ApplicationUser para la organización seleccionada.
Los primeros "proyectos" de Organización a Usuarios, los segundos consultan directamente la tabla de Usuarios.
Solo para una vista alternativa que puede ayudar a algunos programadores funcionales:
-
Select
es elmap
-
SelectMany
esbind
(oflatMap
para su gente Scala / Kotlin)
Un ejemplo más de cómo se puede utilizar SelectMany + Select para acumular datos de objetos de sub array.
Supongamos que tenemos usuarios con sus teléfonos:
class Phone {
public string BasePart = "555-xxx-xxx";
}
class User {
public string Name = "Xxxxx";
public List<Phone> Phones;
}
Ahora debemos seleccionar la base de todos los teléfonos de todos los usuarios:
var usersArray = new List<User>(); // array of arrays
List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
SelectMany()
permite contraer una secuencia multidimensional de una manera que de otro modo requeriría un segundo Select()
o un bucle.
Más detalles en esta entrada de blog .
SelectMany
aplana 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 });
var players = db.SoccerTeams.Where( c=> c.Country == "Spain")
.SelectMany( c => c.players);
foreach(var player in players)
{
Console.WriteLine( player.LastName);
}
- De Gea
- Alba
- Costa
- Villa
- Busquets
...