actualización: Como otros han señalado, con el fin de un diccionario para ser verdaderamente "reversible" de esta manera, los valores de en sus List<string>
objetos tienen que ser todos únicos; de lo contrario, no puede crear un Dictionary<string, string>
con una entrada para cada valor en su diccionario de origen, ya que habría claves duplicadas.
Ejemplo:
var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1", "a2" } } // duplicate!
};
que tiene (al menos) dos opciones para hacer frente a esto.
Opción 1: El tiro en los duplicados
Es posible que desee asegurarse de que todos los elementos de cada List<string>
es, de hecho, única. En este caso, un simple SelectMany
con un ToDictionary
logrará lo que necesita; la llamada ToDictionary
lanzará una ArgumentException
al encontrarse con un valor duplicado:
var dictTwo = dictOne
.SelectMany(kvp => kvp.Value.Select(s => new { Key = s, Value = kvp.Key }))
.ToDictionary(x => x.Key, x => x.Value);
La forma más genérica (que viene a la mente) para abstraer esta funcionalidad en su propio método sería la de poner en práctica un método de extensión que hace esto para cualquier IDictionary<T, TEnumerable>
aplicación donde TEnumerable
implementa IEnumerable<TValue>
:
// Code uglified to fit within horizonal scroll area
public static Dictionary<T2, T1> ReverseDictionary<T1, T2, TEnumerable>(
this IDictionary<T1, TEnumerable> source) where TEnumerable : IEnumerable<T2>
{
return source
.SelectMany(e => e.Value.Select(s => new { Key = s, Value = e.Key }))
.ToDictionary(x => x.Key, x => x.Value);
}
feo la proliferación de parámetros de tipo genérico en el método anterior es para permitir tipos distintos de estrictamente Dictionary<T, List<T>>
: podría aceptar una Dictionary<int, string[]>
, por ejemplo, o SortedList<string, Queue<DateTime>>
- solo un par de ejemplos arbitrarios para demostrar su flexibilidad.
(Un programa de pruebas que ilustran este método es en la parte inferior de esta respuesta.)
Opción 2: Skip duplica
Si los elementos duplicados en sus List<string>
valores es un escenario realista que usted quiere ser capaz para manejar sin lanzar una excepción, le sugiero que eche un vistazo a Gabe's excellent answer para un enfoque que utiliza GroupBy
(en realidad, Gabe también proporciona un enfoque flexible que puede cubrir cualquiera de estos dos casos en función de un selector; sin embargo, si definitivamente quiero tirar en un duplicado, aún así sugeriría el abov e enfoque, ya que debe ser algo más barato que usar GroupBy
).
programa Ejemplo
Aquí está un pequeño programa de prueba que ilustra Opción 1 anteriormente en un Dictionary<string, List<string>>
con no hay elementos duplicados en sus List<string>
valores:
var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1" } }
};
// Using ReverseDictionary implementation described above:
var dictTwo = dictOne.ReverseDictionary<string, string, List<string>>();
foreach (var entry in dictTwo)
{
Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
}
de salida:
a1: A
a2: A
b1: B
b2: B
c1: C
¿Hay alguna razón específica por la que deba hacerse en LINQ? –
@ Michael Shimmins: Ahora estoy usando el bucle foreach. está tomando más tiempo para competir la ejecución (tengo más de 2000 claves y cada valor (Lista) contiene al menos 5 elementos) –
Dudo que LINQ sea más rápido, probablemente sea más lento. –