2011-01-18 11 views
13

Tengo un diccionario que contiene pares de valores clave.¿Cómo obtengo la clave anterior de SortedDictionary?

SortedDictionary<int,int> dictionary=new SortedDictionary<int,int>(); 
dictionary.Add(1,33); 
dictionary.Add(2,20); 
dictionary.Add(4,35); 

Quiero obtener un par de valores clave previo de un valor de clave conocido. En el caso anterior, si tengo la clave 4, ¿cómo puedo obtener <2,20>?

+0

SortedDictionary diccionario = new SortedDictionary (); – PramodChoudhari

+2

Me atrevo a preguntar "¿Por qué?" –

+1

Creo que las respuestas a [esta pregunta] (http://stackoverflow.com/questions/931891/sorted-dictionary-in-c) explican cómo hacer lo que desea. –

Respuesta

7

Es difícil implementar esto de manera eficiente con un SortedDictionary<TKey, TValue> ya que se implementa como un árbol binario de búsqueda que no exponga predecesores o sucesores.

Por supuesto, puede simplemente enumerar cada KeyValuePair hasta que encuentre la clave "conocida". Con un poco de LINQ, esto se vería así (suponiendo que la clave sin duda existe y no es la primera clave):

SortedDictionary<int, int> dictionary = ... 
int knownKey = ... 

var previousKvp = dictionary.TakeWhile(kvp => kvp.Key != knownKey) 
          .Last(); 

Si estos supuestos no se sostienen, se podría hacer:

var maybePreviousKvp = dictionary.TakeWhile(kvp => kvp.Key != knownKey) 
           .Cast<KeyValuePair<int, int>?>() 
           .LastOrDefault(); 

(Compruebe que maybePreviousKvp != null comprobar que la KeyValuePair anterior fue recuperado satisfactoriamente.)

Pero esto no va a ser eficiente en absoluto.


Si es posible, considere el uso de un SortedList<TKey, TValue> lugar (obviamente, esto puede no ser posible si usted no puede tomar sus inserciones y eliminaciones más lentos). Esta colección admite claves eficientes y recuperación de valores por ordenado índice ya que se implementa como una matriz cultivable. A continuación, la consulta se vuelve tan simple como:

SortedList<int, int> dictionary = ... 
int knownKey = ... 

int indexOfPrevious = dictionary.IndexOfKey(knownKey) - 1; 

// if "known" key exists and isn't the first key 
if(indexOfPrevious >= 0) 
{ 
    // Wrap these in a KeyValuePair if necessary 
    int previousKey = dictionary.Keys[indexOfPrevious]; 
    int previousValue = dictionary.Values[indexOfPrevious];  
} 

ejecuta una búsqueda binaria sobre las teclas de vinos, lo que se ejecuta en O(log n) tiempo. Todo lo demás debería ejecutarse en tiempo constante, lo que significa que toda la operación debería ejecutarse en tiempo logarítmico.


De lo contrario, tendrá que aplicar a sí mismo/BST encontrar una colección que hace exponer predecesores/sucesores.

1

Dictionary<TKey,TValue> no está clasificado, por lo que no hay anterior cosa para algún artículo. En su lugar, puede usar SortedDictionary<TKey,TValue>.

EDIT: siento haber leído el título solo jajaja.

Si usted tiene que uso de LINQ:

int givenKey = 4; 
var previousItem = dict.Where((pair, index) => 
            index == dict.Count || 
            dict.ElementAt(index + 1).Key == givenKey) 
         .FirstOrDefault(); 
+2

Él ya está usando el SortedDictionary. –

+0

Sí, ya estoy usando SortedDictionary. – PramodChoudhari

+0

Intenté usar esto en una función que aceptaba 'dict' y' givenKey' como mi Diccionario y la clave desde la que comenzaba, y para devolver 'previousItem' como una cadena, ya que tengo un diccionario de' ' . Aparece un error: 'No se puede convertir implícitamente el tipo 'System.Collections.Generic.KeyValuePair ' to 'string''. Así que esto no solo devuelve la clave, sino que confirmó que devuelve todo el KeyValuePair. Entonces en mi caso, hice 'KeyValuePair tempKVP = MoveToPreviousKey (myDict, givenKey);' y luego 'string previousKey = tempKVP.Key;'. Funcionó muy bien. HTH alguien. – vapcguy

1

Se puede recorrer el diccionario y realizar un seguimiento de los valores, supongo. Algo como esto:

public int GetPreviousKey(int currentKey, SortedDictionary<int, int> dictionary) 
{ 
    int previousKey = int.MinValue; 
    foreach(KeyValuePair<int,int> pair in dictionary) 
    { 
     if(pair.Key == currentKey) 
     { 
      if(previousKey == int.MinValue) 
      { 
       throw new InvalidOperationException("There is no previous key."); 
      } 
      return previousKey; 
     } 
     else 
     { 
      previousKey = pair.Key; 
     } 
    } 
} 

Sin embargo, esta es una operación bastante extraña para requerir. El hecho de que lo necesite podría estar apuntando a un problema con su diseño.

+0

Hola querido, tu solución está funcionando thankx alots ... :) – PramodChoudhari

4
KeyValuePair<int, int> lookingForThis = dictionary 
    .Reverse() 
    .SkipWhile(kvp => kvp.Key != 4) 
    .Skip(1) 
    .FirstOrDefault(); 
+0

+1. Solo quisiera señalar que la pregunta del OP realmente no tiene sentido. Mientras que esta respuesta volverá, se emparejaron antes, el par anterior cambiará continuamente a medida que agrega elementos al diccionario. Creo que se necesita más aclaración sobre lo que el OP está tratando de hacer – Rob

+0

--------------- – TomTom

+2

Creo que debería ser '.SkipWhile (kvp => kvp.Key! = 4) .Skip (1) ' – Gabe

1

Preferiría usar linq si ese es el caso ...intente esto seguramente funcionará

SortedDictionary<int,int> dictionary = new SortedDictionary<int,int>(); 
dictionary.add(1, 33); 
dictionary.add(2, 20); 
dictionary.add(4, 35); 

int SelectedKey = 4; 

var ResutValue = (from n in dictionary  
       where n.Key < TheSelectedKey 
       select n.Value).Last(); 

this.txtResult.Text = ResultValue.ToString(); 
0

¿Qué le parece esto? No lo he probado, pero debería dar algo para empezar a pensar en esta dirección. Espero eso ayude.

 int input = 4; 
     List<int> lKeys = dictionary.Keys.ToList(); 
     int reqIndex = lKeys.IndexOf(input) - 1; 
     int reqAnswer = dictionary[reqIndex]; 

prueba para otras condiciones como si (reqIndex! = -1), etc ..

5

También estaba buscando una respuesta a este problema, y ​​pensé que una solución mejor que todas las respuestas aquí es usar el TreeDictionary<K, V> del C5 Collections (GitHub/NuGet), que es una implementación de un árbol rojo-negro.

Tiene Predecessor/TryPredecessor y WeakPredessor/TryWeakPredecessor métodos (así como métodos equivalentes para los sucesores) que hace exactamente lo que quiere.

Por ejemplo:

TreeDictionary<int,int> dictionary = new TreeDictionary<int,int>(); 
dictionary.Add(1,33); 
dictionary.Add(2,20); 
dictionary.Add(4,35); 

// applied to the dictionary itself, returns KeyValuePair<int,int> 
var previousValue = dictionary.Predecessor(4); 
Assert.Equals(previousValue.Key, 2); 
Assert.Equals(previousValue.Value, 20); 

// applied to the keys of the dictionary, returns key only 
var previousKey = dictionary.Keys.Predecessor(4); 
Assert.Equals(previousKey, 2); 

// it is also possible to specify keys not in the dictionary 
previousKey = dictionary.Keys.Predecessor(3); 
Assert.Equals(previousKey, 2); 
+3

En caso de que alguien no sepa qué es un predecesor débil, es el primer elemento ** igual o inferior a ** el valor aprobado. Un predecesor (estricto) es el artículo justo ** menor que ** el valor pasado. De manera similar para los sucesores. – nawfal

Cuestiones relacionadas