2009-08-31 13 views
5

Attualmente sto cercando di creare un programma che stima la posizione in base alla potenza del segnale. Il valore di intensità del segnale è un int e quindi ho bisogno di un dizionario di ricerca con intervalli.C# Cerca dizionario

Quindi mi sento di avere qualcosa di simile:

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

e poi vorrei cercare quale sia la posizione di una potenza del segnale si riferisce, ad esempio 15 si riferirebbe in posizione 2.

So può avere solo un carico di istruzioni if, ma c'è un buon modo per farlo usando una sorta di dizionario di ricerca?

risposta

11

Se si dispone intervalli arbitrari ma consecutivi si può utilizzare una matrice dei limiti superiori ed eseguire una ricerca binaria per ottenere la posizione:

// 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 restituisce l'indice dell'elemento nell'array se esiste (l'array deve essere ordinato ovviamente) o l'indice invertito bit a bit in cui l'elemento deve essere inserito per mantenere ordinato l'array.

+0

Ulteriori spiegazioni renderebbero questa una risposta ideale. –

+1

Buona risposta. Funzionerebbe con qualsiasi insieme di intervalli arbitrari che non hanno spazi vuoti tra loro. – jrista

+0

Grazie, è possibile utilizzare qualcosa di simile a questo se le posizioni sono nominate piuttosto che un numero che aumenta di uno? – DNN

11

Che dire:

int position = signalStrength/10 + 1; 

Gentilezza,

Dan

+2

Risposta eccellente, supponendo che gli intervalli siano effettivamente in gruppi di 10 e che non fosse solo un'anomalia campione. –

+0

Man mano che la forza aumenta, non saranno sempre tra 10 secondi. Mi piace la risposta però – DNN

0

Si potrebbe fare un dizionario, dove il primo int è la potenza del segnale e la seconda è la posizione int. Dovresti aggiungere una voce per ogni valore nell'intervallo (quindi, uno per la forza del segnale 0, la posizione 1, l'intensità del segnale 1, la posizione 1, ecc.), Ma sarebbe una rapida ricerca a linea singola.

Qualcosa di simile:

Dictionary<int, int> values; 

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

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

e poi, per accedervi:

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

Provare a utilizzare farmaci generici:

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); 

ecc

Poi, ricerca [22] restituirebbe il valore di 3. I sug gest usando un insieme di loop per creare le tue "gamme". Con questo metodo, hai tempo di accesso O (1) garantito.

+1

Stai seriamente suggerendo di aggiungere valori distinti al Dizionario per ogni valore integrale nei suoi intervalli? –

+0

Sì. Per un numero limitato di intervalli, potrebbe essere ciò che l'OP sta cercando. hai una soluzione migliore? Se è così, posta. –

+0

@Charlie: Non c'è bisogno che echi le risposte che sono già state inviate da dtb e agileguy. –

0

Per espansione futura vorrei fare 2 dizionari. Nel caso in cui tali tassi cambiano così un

dictionary<string,dictionary<int,int>> 

o semplicemente usare le classi personalizzate la stringa sarebbe stringhe statiche come LOW MED, alto, allora è possibile modificare gli intervalli nel foreach initilixing i valori iniziali

1

Il buono è una funzione di scopo. Tutte le soluzioni di cui sopra funzionano bene presumendo che ogni intervallo dato sia un piccolo numero di numeri interi. Altrimenti potresti voler usare qualsiasi cosa sia la funzione matematica del mondo reale per determinare il tuo gruppo. Ad esempio, per l'esempio fornito, la tua funzione di risposta sarebbe x% 10 + 1; Funzionerà molto più velocemente di un dizionario.

0

Una soluzione sarebbe utilizzare un elenco semplice, in cui ogni posizione nell'elenco rappresenta una posizione diversa per la quale si sta eseguendo la scansione. Nel codice, potrebbe sembrare qualcosa del genere (supponendo che tutti i numeri di posizione siano sequenziali):

** Nota: non ho ancora eseguito questo codice per assicurarmi che funzioni così com'è ... potrebbe anche essere necessario implementare un IEqualityComparer su Range in modo che l'operazione IndexOf per restituire la posizione corretta:

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; 
    } 
}

probabilmente è abbastanza auto-esplicativo, ma per evitare qualsiasi confusione, ecco ciò che la classe Range potrebbe essere simile:

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

se esiste una correlazione diretta tra l'intervallo del segnale e la posizione, utilizzare ciò che suggerito da @agileguy.

Se avete posizioni distribuiti in modo non lineare in tutta la potenza del segnale di un modo potrebbe essere:

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

Quando si desidera utilizzare il dizionario, è necessario almeno un certo tipo di chiave speciale per affrontare le gamme. KeyType può essere astratto e due tipi derivati ​​KeyTypeRange (int int) e KEyTypeSearch (int). Alcune logiche di confronto particolari devono essere implementate per confrontare 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)); 

Mostra una possibile soluzione per utilizzare diverse chiavi esearch e valori chiave nei dizionari. Ma questo sembra essere Overkill per questo problema. Questo problema è risolto al meglio dalla soluzione BinarySearch.

+0

Bene menzionare questo approccio. Preferisco la ricerca binaria ma è bene sottolineare usando KeyTypeRange invece di caricare un dizionario con tutti i valori possibili come menzionato in precedenza. – Steve

+0

@Thomas: Sembra interessante. Puoi elaborare la tua idea? 'Dizionario ' è implementato come tabella hash. Come implementate 'GetHashCode' di' KeyTypeRange' e 'KeyTypeSearch' in modo che' new KeyTypeSearch (15) 'produca' new KeyTypeRange (1,10) '? – dtb

+0

In effetti non è possibile utilizzare il dizionario , è necessario utilizzare SortedDictionary , perché non è possibile fornire una funzione hash per questo problema. Le chiavi SortedDictionary sono confrontate con IComparer . Compare (T x, T y) che è facile da implementare. –