8

soy capaz de ordenar mi ConcurrentDictionary por el valor de este modo:Ordenar una ConcurrentDictionary por valor

static ConcurrentDictionary<string, Proxy> Proxies = 
    new ConcurrentDictionary<string, Proxy>(); 

Proxies.OrderBy(p => p.Value.Speed); 

cual es genial, excepto que quiero establecer que la nueva lista reordenada como el diccionario, la clasificación de manera efectiva el diccionario en vez de solo recibir una lista de resultados de los artículos clasificados.

trato de hacer algo como esto, pero no tuvo suerte - el diccionario sigue siendo desordenada después:

Proxies = new ConcurrentDictionary<string,Proxy>(
    Proxies.OrderBy(p => p.Value.Speed)); 

Parece como hacer que no tiene ningún efecto en el diccionario. También intenté enviar el resultado de OrderBy a una nueva var pensando que podría tener un efecto en el delegado, pero aún no tuvo suerte.

¿Cómo puedo volver a solicitar este ConcurrentDictionary y luego forzar que el diccionario sea el resultado reordenado de OrderBy?

+0

Si necesita las propiedades de acceso rápido de un diccionario, combinada con hilos de seguridad y clasificación continua, necesita algo así como un árbol B concurrente. No creo que haya uno disponible en .NET. ¿Quizás tercero? ¿Alguna posibilidad de que simplemente use OrderBy() cuando necesite los resultados? – Timo

Respuesta

6

Los diccionarios simples no son colecciones ordenadas. Son simplemente una colección que mapea las claves de los valores. ConcurrentDictionary no es diferente.

En su lugar, necesitaría un SortedConcurrentDictionary (similar a SortedDictionary), sin embargo, esta estructura de datos no existe.

En cuanto a si realmente necesita un "diccionario" ordenado, tendremos que saber más sobre su caso de uso. ¿Es esto una cola de prioridad de falsa? ¿Podría simplemente usar un ConcurrentBag<Proxy> y realizar el pedido después del hecho?

Si necesita tomar la colección y en un método paralelo en sentido descendente utilice los proxies en orden ordenado, sugiero echar un vistazo a la creación de un custom Partitioner, posiblemente tomando prestado del MSDN example of an OrderablePartitioner.

+0

El diccionario solo se usa para evitar que se agreguen valores duplicados. Anteriormente, simplemente estaba usando una lista y comprobando si los valores existían antes de agregar. Podría usar un ConcurrentBag , pero eso requeriría el uso de dos listas separadas, ya que mantengo una vista activa y visible de los proxies en un ListView, lo que permite ver/administrar los proxies/etc. La implementación anterior de la Lista con mecanismos de bloqueo funcionaba bastante bien hasta que llegué a un error recientemente con elementos nulos, así que traté de cambiar a un ConcurrentBag/Dictionary/etc ... – user1111380

+0

Así que parece que necesitabas un ' HashSet', que el 'ConcurrentBag' no es como usted lo encontró. ¿Esto es concurrente porque viene otro hilo y lo actualiza? – user7116

+0

Rgiht, estoy usando múltiples hilos para verificar los proxies y actualizar la lista en consecuencia. – user1111380

0

ConcurrentDictionary, al igual que Dictionary, no conoce el concepto de clasificación, es decir, no contiene ningún tipo de información de pedido. El resultado de OrderBy() tiene un orden específico, pero cuando se asigna a Proxies se pierde la información del pedido.

Tenga en cuenta que hay implementaciones ordenadas de IDictionary, es decir, SortedDictionary y SortedList.

+0

Sin duda, este es un problema que el equipo BCL puede investigar. – Eniola

2

Un diccionario, especialmente ConcurrentDictionary, es esencialmente desordenado.

Si necesita una colección ordenada, deberá almacenar los valores en algún otro tipo, como SortedDictionary<T,U>.

+0

Esperaba utilizar la concurrencia .NET incorporada ofrecida por ConcurrentDictionary, sin embargo. Puedo ver que esto no es posible mientras ofrezco capacidades ordenadas. Volver a usar las declaraciones lock() ... gracias. – user1111380

+1

@ user1111380 Solo tenga cuidado: los pedidos y las colecciones simultáneas generalmente entran en conflicto ... Normalmente, cuando sea posible, es una buena idea mantener sus datos en una colección simultánea mientras se trabaja en ellos, luego extraer los elementos en un orden específico para presentar los resultados , etc. –

+0

Pero recuperar elementos en un orden determinado donde trabajar con la colección es más intensivo en lectura que escribir intensivamente puede ser bastante caro. Veo un caso para querer actualizar un ConcurrentDictionary y hacer que la clasificación de los elementos sea atómicamente parte de la actualización. En lugar de tener que reiniciar todo el Diccionario en el orden de clasificación deseado. Con ese fin, ConcurrentSortedDictionary u SortedConcurrentDictionary serán agradables en el BCL. – Eniola

2

La solución es utilizar un SortedSet<T>, descubierto después de muchas horas de investigación y revisión del código. Un conjunto ordenado ofrece la exclusividad de Dictionary o HashSet, pero también permite la clasificación: ni un Dictionary ni un HashSet permiten la clasificación.

+2

¿Excepto que un SortedSet no es concurrente? Creo que tener una colección que admita la clasificación y que sea simultánea es un elemento esencial en nuestra bolsa de herramientas. Creo que deberíamos alentar al equipo de BCL a echarle un vistazo a esto. – Eniola

1

Tal vez no es eficiente si se llama a menudo en una clase inmutable, pero simple:

Imports System.Collections.Concurrent 

Public Class SortedConcurrentDictionary(Of TKey, Tvalue) 
Inherits ConcurrentDictionary(Of TKey, Tvalue) 

    Shadows ReadOnly Property Values As IEnumerable(Of Tvalue) 
     Get 
      If MyBase.Values.Count = 0 Then 
       Return MyBase.Values 
      End If 
      Return From k In Keys Order By k Select Me(k) 
     End Get 
    End Property 
End Class 
+0

Una idea interesante, pero ¿qué tan eficiente es esto? Parece que las claves se ordenan en cada enumeración de los contenidos? – Eniola

+0

@Eniola Tienes razón, como dije, "Quizás no sea eficiente". Una versión más sofisticada almacenaría en caché y actualizaría la caché cuando se cambiara el ditionary. – smirkingman

Cuestiones relacionadas