Sí - use Dictionary.TryGetValue
. Toma un parámetro out
para recibir el valor y devuelve si se encontró el valor o no. Aquí está el código ajustado:
foreach(var item in newInfo)
{
int value;
if (myDict.TryGetValue(item.Name, out value))
{
myDict[item.Name] = value + item.NewInfo;
}
else
{
myDict[item.Name] = item.NewInfo;
}
}
Sin embargo, podemos hacerlo mejor que eso en este caso particular,. Si la clave no está, el parámetro out
se establece en 0. Como vamos a establecer el nuevo valor en item.NewInfo
o item.NewInfo + value
, realmente estamos haciendo lo mismo. Podemos pasar por alto el valor de retorno del método, y sólo tiene que utilizar:
foreach(var item in newInfo)
{
int value;
myDict.TryGetValue(item.Name, out value);
myDict[item.Name] = value + item.NewInfo;
}
que es bastante inusual, aunque - por lo general se le utilizar el valor de retorno, obviamente.
Digresión
Es sólo porque en realidad está haciendo una operación GetValueOrDefault
que funciona. De hecho, eso sería un par válido de los métodos de extensión:
public static TValue GetValueOrDefault<TKey, TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key)
{
TValue value;
dictionary.TryGetValue(key, out value);
return value;
}
public static TValue GetValueOrDefault<TKey, TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key,
TValue customDefault)
{
TValue value;
if (dictionary.TryGetValue(key, out value))
{
return value;
}
else
{
return customDefault;
}
}
En ese momento usted puede hacer su código claro y concisa:
foreach(var item in newInfo)
{
myDict[item.Name] = myDict.GetValueOrDefault(item.Name) + item.NewInfo;
}
(que se podría llamar GetValueOrDefault(item.Name, 0)
para potencialmente más claridad .)
Volver al punto ...
Tenga en cuenta que todavía está haciendo dos búsquedas, una para obtener el valor y otra para agregar/reemplazar. Realmente no se puede evitar eso sin hacer que el argumento de tipo TValue
sea mutable, lo que podría cambiar en su lugar. Eso sería posible, pero no terriblemente agradable.
En el código original, está realizando potencialmente tres búsquedas - una para ContainsKey
, y luego dos (si se encuentra la clave) para reemplazar el valor. Es más fácil ver que si ampliamos la +=
:
myDict[item.Name] = myDict[item.Name] + item.NewInfo;
(. item.Name
solamente sería evaluado una vez, pero aparte de eso es lo mismo)
Otra digresión
que habría bueno tener una operación en Dictionary
que hizo una "búsqueda y reemplazo" en función de una función para obtener el nuevo valor basado en el anterior, por ejemplo
bool Update(TKey key, Func<TValue, bool, TValue> replacementFunction)
donde replacementFunction
sería una función de tomar el valor actual (o el valor por defecto de TValue
si no se ha encontrado la clave) y un booleano para decir si o no la tecla se encontró realmente, y vuelve el nuevo valor El diccionario podría buscar la clave, llamar a la función de reemplazo y actualizar el valor en su lugar. (Esto no se puede implementar como un método de extensión.)
Si bien esto es funcional, acaba de ser conscientes de que el valor sólo es 0 porque el valor predeterminado para el tipo int es 0. Desde una perspectiva de codificación defensiva, esto sacrifica la legibilidad (y potencialmente de mantenimiento) para la concisión. Me quedaría con lo que tienes, para ser sincero. –
Voy a dar una advertencia más grande: ciertamente es un caso especial. –
¿Todavía no has hashing cada elemento dos veces? Una vez en TryGetValue, y de nuevo donde dices 'myDict [item.Name]'? –