c# - concurrent - ¿Cuál es la forma más rápida de generar un conjunto único en.NET 2
list c# (6)
Use KeyValuePair como una clase contenedora y luego cree un diccionario para crear un conjunto tal vez? O implemente su propio contenedor que anule Iguales y GetHashCode.
Dictionary<KeyValuePair, bool> mySet;
for(int i = 0; i < keys.length; ++i)
{
KeyValuePair kvp = new KeyValuePair(keys[i], values[i]);
mySet[kvp] = true;
}
Tengo lo que es esencialmente una matriz dentada de pares de valores de nombres; necesito generar un conjunto de valores de nombres únicos a partir de esto. la matriz dentada tiene aproximadamente 86,000 x 11 valores. No me importa de qué manera tengo que almacenar un par de nombre y valor (una sola cadena "name = value" o una clase especializada, por ejemplo KeyValuePair).
Información adicional: hay 40 nombres distintos y un número mayor de valores distintos, probablemente en la región 10,000 valores.
Estoy usando C # y .NET 2.0 (y el rendimiento es tan bajo que estoy pensando que puede ser mejor insertar toda mi matriz dentada en una base de datos sql y hacer una selección distinta desde allí).
Debajo está el código actual que estoy usando:
List<List<KeyValuePair<string,string>>> vehicleList = retriever.GetVehicles();
this.statsLabel.Text = "Unique Vehicles: " + vehicleList.Count;
Dictionary<KeyValuePair<string, string>, int> uniqueProperties = new Dictionary<KeyValuePair<string, string>, int>();
foreach (List<KeyValuePair<string, string>> vehicle in vehicleList)
{
foreach (KeyValuePair<string, string> property in vehicle)
{
if (!uniqueProperties.ContainsKey(property))
{
uniqueProperties.Add(property, 0);
}
}
}
this.statsLabel.Text += "/rUnique Properties: " + uniqueProperties.Count;
si no necesita una correlación específica entre cada par de clave / valor y los valores únicos que está generando, podría simplemente usar un GUID? Supongo que el problema es que su ''Clave'' actual no es única en esta matriz dentada.
Dictionary<System.Guid, KeyValuePair<string, string>> myDict
= new Dictionary<Guid, KeyValuePair<string, string>>();
foreach of your key values in their current format
myDict.Add(System.Guid.NewGuid(), new KeyValuePair<string, string>(yourKey, yourvalue))
Parece que almacenaría lo que necesita, pero no sé cómo extraería datos de esto, ya que no habría relación semántica entre Gene Guid y lo que originalmente tenía ...
¿Puedes proporcionar más información en tu pregunta?
¿Has perfilado tu código? Está seguro de que los bucles foreach son el cuello de botella y no el recuperador. GetVehicles ()?
Creé un pequeño proyecto de prueba donde falsifico el retriever y lo dejo devolver 86,000 X 11 valores. Mi primer intento se ejecutó en 5 segundos, creando los datos incluidos.
Usé el mismo valor para la clave y el valor donde la primera clave era "0 # 0" y la última "85999 # 10".
Luego cambié a las guías. Mismo resultado.
Luego hice la clave más tiempo, así:
var s = Guid.NewGuid().ToString();
return s + s + s + s + s + s + s+ s + s + s;
Ahora tomó casi 10 segundos.
Luego hice las teclas increíblemente largas y obtuve una excepción de falta de memoria. No tengo un archivo de intercambio en mi computadora, así que obtuve esta excepción de inmediato.
¿Cuánto duran tus llaves? ¿El consumo de memoria virtual es el motivo de tu bajo rendimiento?
Lo tengo funcionando en 0.34 segundos desde 9+ minutos
El problema es cuando se comparan las estructuras de KeyValuePair. Trabajé alrededor escribiendo un objeto comparador y pasando una instancia de él al Diccionario.
Según lo que puedo determinar, KeyValuePair.GetHashCode () devuelve el código de su objeto Key
(en este ejemplo, el objeto menos exclusivo).
A medida que el diccionario agrega (y comprueba la existencia de) cada elemento, usa las funciones Equal y GetHashCode, pero tiene que confiar en la función Equals cuando el código hash es menos único.
Al proporcionar una función GetHashCode más única, utiliza la función Equals con mucha menos frecuencia. También optimicé la función Equals para comparar los valores más únicos antes de las claves menos unqiue.
86,000 * 11 elementos con 10,000 propiedades únicas se ejecutan en 0.34 segundos usando el objeto comparer a continuación (sin el objeto comparer toma 9 minutos 22 segundos)
Espero que esto ayude :)
class StringPairComparer
: IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Value == y.Value && x.Key == y.Key;
}
public int GetHashCode(KeyValuePair<string, string> obj)
{
return (obj.Key + obj.Value).GetHashCode();
}
}
EDITAR : Si fuera solo una cadena (en lugar de un KeyValuePair, donde string = Name + Value) sería aproximadamente dos veces más rápido. Es un buen problema interesante, y he pasado demasiado tiempo en él (aunque aprendí un poco de calma)
En lugar de utilizar un Dictionary
¿por qué no ampliar KeyedCollection<TKey, TItem>
? De acuerdo con la documentación:
Proporciona la clase base abstracta para una colección cuyas claves están incrustadas en los valores.
Luego debe sobrescribir la protected TKey GetKeyForItem(TItem item)
. Como es un híbrido entre IList<T>
e IDictionary<TKey, TValue>
Creo que es bastante rápido.
Qué tal si:
Dictionary<NameValuePair,int> hs = new Dictionary<NameValuePair,int>();
foreach (i in jaggedArray)
{
foreach (j in i)
{
if (!hs.ContainsKey(j))
{
hs.Add(j, 0);
}
}
}
IEnumerable<NameValuePair> unique = hs.Keys;
por supuesto, si estabas usando C # 3.0, .NET 3.5:
var hs = new HashSet<NameValuePair>();
hs.UnionWith(jaggedArray.SelectMany(item => item));
Haría el truco.