c# - query - Mejor rendimiento en la actualización de objetos con linq
how to optimize linq query (3)
Esa unión debe ser bastante rápida, ya que primero recorrerá todo el adjList
para crear una búsqueda, luego, para cada elemento en propList
, solo usará la búsqueda. Esto es más rápido que su método O (N * M) en el código más grande, aunque eso podría solucionarse fácilmente llamando a ToLookup
(o ToDictionary
ya que solo necesita un valor) en adjList
antes del bucle.
EDITAR: Aquí está el código modificado usando ToDictionary
. No probado, fíjate ...
var adjDictionary = adjList.ToDictionary(av => av.PropName);
foreach (var p in propList)
{
Adjustment a;
if (adjDictionary.TryGetValue(p.Name, out a))
{
p.Total = p.Val + a.AdjVal;
}
else
{
p.Total = p.Val;
}
}
Tengo dos listas de objetos personalizados y quiero actualizar un campo para todos los objetos en una lista si hay un objeto en la otra lista que coincida con otro par de campos.
Este código explica mejor el problema y produce los resultados que quiero. Sin embargo, para listas más grandes 20k y una lista de 20k con objetos coincidentes, esto lleva un tiempo considerable (31s). Puedo mejorar esto con ~ 50% mediante el método de listas genéricas Buscar (predicado).
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
namespace ExperimentFW3
{
public class PropValue
{
public string Name;
public decimal Val;
public decimal Total;
}
public class Adjustment
{
public string PropName;
public decimal AdjVal;
}
class Program
{
static List<PropValue> propList;
static List<Adjustment> adjList;
public static void Main()
{
propList = new List<PropValue>{
new PropValue{Name = "Alfa", Val=2.1M},
new PropValue{Name = "Beta", Val=1.0M},
new PropValue{Name = "Gamma", Val=8.0M}
};
adjList = new List<Adjustment>{
new Adjustment{PropName = "Alfa", AdjVal=-0.1M},
new Adjustment{PropName = "Beta", AdjVal=3M}
};
foreach (var p in propList)
{
Adjustment a = adjList.SingleOrDefault(
av => av.PropName.Equals(p.Name)
);
if (a != null)
p.Total = p.Val + a.AdjVal;
else
p.Total = p.Val;
}
}
}
}
El resultado deseado es: Alfa total = 2, Beta total = 4, Gamma total = 8
Pero me pregunto si esto es posible hacerlo aún más rápido. La unión interna de las dos listas lleva muy poco tiempo, incluso cuando se repiten más de 20 elementos en el conjunto de resultados.
var joined = from p in propList
join a in adjList on p.Name equals a.PropName
select new { p.Name, p.Val, p.Total, a.AdjVal };
Entonces mi pregunta es si es posible hacer algo como lo haría con T-SQL. Una ACTUALIZACIÓN de una combinación a la izquierda que usa ISNULL (val, 0) en el valor de ajuste.
Si adjList puede tener nombres duplicados, debe agrupar los elementos antes de pasar al diccionario.
Dictionary<string, decimal> adjDictionary = adjList
.GroupBy(a => a.PropName)
.ToDictionary(g => g.Key, g => g.Sum(a => a.AdjVal))
propList.ForEach(p =>
{
decimal a;
adjDictionary.TryGetValue(p.Name, out a);
p.Total = p.Val + a;
});
Sé que llego tarde publicando esto, pero pensé que alguien apreciaría la respuesta corta más clara a continuación que maneja múltiples registros por búsqueda en adjList. La creación de un LookUp permitirá realizar búsquedas rápidas en varios elementos y devolverá una lista vacía si no hay registros en LookUp.
var adjLookUp = adjList.ToLookUp(a => a.PropName);
foreach (var p in propList)
p.Total = p.Val + adjLookUp[p.Name].Sum(a => a.AdjVal);