2009-08-31 16 views
5

Actualmente estoy tratando de crear un programa que estima la ubicación en función de la intensidad de la señal. El valor de intensidad de señal es un int y luego necesito un diccionario de búsqueda con rangos.C# Buscar diccionario

Así que me gustaría tener algo como:

Signal Strenth    Position 
0-9       1 
10-19       2 
20-29       3 

y luego me gustaría ver cuál es la posición de una intensidad de la señal se refiere a, por ejemplo, 15 se refieren a la posición 2.

Sé que solo puede tener una carga de instrucciones if, pero ¿hay una buena manera de hacerlo utilizando algún tipo de diccionario de búsqueda?

Respuesta

11

Si tiene rangos arbitrarios consecutivos, pero se puede utilizar una matriz de los límites superiores y realizar una búsqueda binaria para obtener la posición:

// Definition of ranges 
int[] ranges = new int[] { 9, 19, 29 }; 

// Lookup 
int position = Array.BinarySearch(ranges, 15); 
if (position < 0) 
    position = ~position; 

// Definition of range names 
string[] names = new string[] { "home", "street", "city", "far away" }; 

Console.WriteLine("Position is: {0}", names[position]); 

Array.BinarySearch devuelve el índice del elemento en la matriz, si existe (la matriz se debe ordenar de forma obvia) o el índice invertido bit a bit donde se debe insertar el elemento para mantener la matriz ordenada.

+0

Más explicaciones hacen que esta sea una respuesta ideal. –

+1

Buena respuesta. Funcionaría con cualquier conjunto de rangos arbitrarios que no tengan vacíos entre ellos. – jrista

+0

Gracias, ¿es posible usar algo similar a esto si se nombran las posiciones en lugar de solo un número que aumenta en uno? – DNN

11

¿Qué hay de:

int position = signalStrength/10 + 1; 

Bondad,

Dan

+2

Excelente respuesta, suponiendo que los rangos en realidad están en grupos de 10 y que no fue solo una anomalía de muestra. –

+0

A medida que la fuerza aumenta, no siempre estarán en 10s. Me gusta la respuesta aunque – DNN

0

Usted podría hacer un diccionario, donde el primer int es la intensidad de la señal y la segunda es la posición int. Necesitaría agregar una entrada para cada valor en el rango (por lo tanto, uno para la intensidad de la señal 0, posición 1, intensidad de señal 1, posición 1, etc.), pero sería una búsqueda de línea única muy rápida.

Algo así como:

Dictionary<int, int> values; 

values = new Dictionary<int, int>(); 

values[0] = 1; 
values[1] = 1; 
... 
values[29] = 3; 

y luego, para acceder a ella:

Console.WriteLine(values[27].ToString()); 
-1

Trate de usar los genéricos:

Dictionary<int,int> lookup = new Dictionary<int,int>(); 
lookup.Add(0,1); 
lookup.Add(1,1); 
lookup.Add(2,1); 
lookup.Add(3,1); 
... 
lookup.Add(9,1); 
lookup.Add(10,2); 
lookup.Add(11,2); 

etc

Entonces, la búsqueda [22] devolvería el valor de 3. Sugiero gest usando un conjunto de bucles para crear sus 'rangos'. Con este método, tiene garantizado O (1) tiempo de acceso.

+1

¿Está sugiriendo seriamente que agregue valores distintos al diccionario para cada valor integral en sus rangos? –

+0

Sí. Para un pequeño número de rangos, puede ser lo que el OP está buscando. ¿Tienes una mejor solución? Si es así, publica. –

+0

@Charlie: No es necesario que repita las respuestas que ya han sido enviadas por dtb y agileguy. –

0

Para una futura expansión, haré 2 diccionarios. Sólo en caso de esas tasas de cambio por lo que un

dictionary<string,dictionary<int,int>> 

o simplemente utilizar clases personalizadas la cadena sería cadenas estáticas como bajas Med, Alto, a continuación, puede cambiar los rangos en su foreach initilixing los valores iniciales

1

Bueno es una función de propósito. Todas las soluciones anteriores funcionan bien suponiendo que cualquier rango dado es un número pequeño de enteros. De lo contrario, puede usar cualquier función matemática del mundo real para determinar su grupo. Por ejemplo, para el ejemplo dado, su función de respuesta sería x% 10 + 1; Eso funcionará mucho más rápido que un diccionario.

0

Una solución sería utilizar una lista simple, donde cada posición en la lista representa una posición diferente que está escaneando. En el código, podría parecerse a esto (suponiendo que todos los números de posición son secuenciales):

** Nota: No he ejecutado este código para asegurarme de que funciona tal como está ... también es posible que necesite implementar un IEqualityComparer en Range a fin de que la operación IndexOf para devolver la posición correcta:

public class Controller 
{ 
    List m_positions = new List(); 

    public void LoadPositions() 
    { 
     m_positions.Add(new Range(0, 9)); 
     m_positions.Add(new Range(10, 19)); 
     m_positions.Add(new Range(20, 29)); 
    } 

    public int GetPosition (int signal) 
    { 
     Range range = m_positions.Single(a => IsBetween(signal, a.Min, a.Max)); 

     return m_positions.IndexOf(range); 
    } 

    private static bool IsBetween (int target, int min, int max) 
    { 
     return min = target; 
    } 
}

es probablemente explica por sí mismo, pero para evitar cualquier confusión, esto es lo que la clase Range podría ser:

public class Range 
{ 
    public Range(int min, int max) 
    { 
     this.Min = min; 
     this.Max = max; 
    } 

    public int Min 
    { 
     get; 
     private set; 
    } 

    public int Max 
    { 
     get; 
     private set; 
    } 
}
0

si existe una correlación directa entre el rango de la señal y la posición, entonces use lo que sugirió @agileguy.

Si ha distribuido posiciones no linealmente a través de la intensidad de la señal a continuación, una solución sería:

class SignalStrengthPositionMapper 
{ 
    private static readonly int[] signalStrength = { Int32.MinValue, 0, 5, 11, 15, 20, 27, 35 }; 
    public static int GetPosition(int strength) 
    { 
     return StrengthSearch(0, signalStrength.Length, strength); 
    } 

    // modified binary search 
    private static int StrengthSearch(int start, int end, int strength) 
    { 
     int mid = 0; 
     while (start <= end) 
     { 
      mid = (start + end)/2; 

      if (strength >= signalStrength[mid])   // lower bound check 
      { 
       start = mid + 1; 
       if (strength < signalStrength[start]) // upper bound check 
        return mid; 
      } 
      else if (strength < signalStrength[mid])  // upper bound check 
      { 
       end = mid - 1; 
       if (strength >= signalStrength[end])  // lower bound check 
        return mid; 
      } 
     } 
     return 0; 
    } 
} 
2

Cuando se desea utilizar el diccionario, necesita al menos algún tipo de clave especial para tratar con los rangos. KeyType puede ser abstracto y dos tipos derivados KeyTypeRange (int int) y KEyTypeSearch (int). Se debe implementar alguna lógica de comparación especial para comparar un KeyTypeSearch con un KeyTypeRange.

SortedDictionary<KeyType,int> lookup = new Dictionary<int,int>(); 
lookup.Add(new KeyTypeRange(1,10),1); 
lookup.Add(new KeyTypeRange(11,20),2); 
lookup.Add(new KeyTypeRange(21,30),3); 
lookup.TryGetValue(new KeyTypeSearch(15)); 

Muestra una posible solución para utilizar diferentes claves de búsqueda y valores de tecla en los diccionarios. Pero esto parece ser Overkill para este problema. Este problema se resuelve mejor con la solución BinarySearch.

+0

Es bueno mencionar este enfoque. Prefiero la búsqueda binaria, pero es bueno señalar usando un KeyTypeRange en lugar de cargar un Dictionary con todos los valores posibles como se mencionó anteriormente. – Steve

+0

@Thomas: Suena interesante. ¿Puedes elaborar tu idea? 'Dictionary ' se implementa como una tabla hash. ¿Cómo se implementa 'GetHashCode' de' KeyTypeRange' y 'KeyTypeSearch' de modo que' new KeyTypeSearch (15) 'arroje' new KeyTypeRange (1,10) '? – dtb

+0

De hecho, no puede usar Dictionary , debe utilizar SortedDictionary , porque no es posible proporcionar una función Hash para este problema. SortedDictionary Keys se comparan por int IComparer .Compare (T x, T y) que es fácil de implementar. –