2009-08-31 2 views
5

В настоящее время я пытаюсь создать программу, которая оценивает местоположение на основе силы сигнала. Значение силы сигнала - это int, а затем мне нужен словарь поиска с диапазонами.C# Поиск словаря

Так что я бы что-то вроде:

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

, а затем я хотел бы посмотреть, что позиция сила сигнала относится, например, 15 будет относиться к позиции 2.

Я знаю, что я может просто загружать инструкции if, но есть ли хороший способ сделать это, используя какой-то словарь поиска?

ответ

11

Если у вас есть произвольные, но последовательные диапазоны вы можете использовать массив из верхних граней и выполнить бинарный поиск, чтобы получить позицию:

// 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 возвращает индекс элемента в массиве, если он существует (массив должен быть отсортирован явно) или побито инвертированный индекс, где элемент должен быть вставлен, чтобы сохранить сортировку массива.

+0

Больше объяснений сделало бы это идеальным ответом. –

+1

Хороший ответ. Будет работать с любым набором произвольных диапазонов, которые не имеют пробелов между ними. – jrista

+0

Спасибо, можно ли использовать что-то подобное этому, если позиции названы, а не просто число, которое увеличивается на единицу? – DNN

11

насчет:

int position = signalStrength/10 + 1; 

Kindness,

Dan

+2

Отличный ответ, предполагая, что диапазоны фактически находятся в группах по 10, и это было не просто аномалиями выборки. –

+0

По мере того как сила становится выше, они не всегда будут в 10 с. Мне нравится ответ, хотя – DNN

0

Вы могли бы сделать словарь, где первая ИНТ сила сигнала и второй ИНТ положение. Вам нужно будет добавить запись для каждого значения в диапазоне (так, один для уровня сигнала 0, позиции 1, уровня сигнала 1, позиции 1 и т. Д.), Но это будет очень быстрый однолинейный поиск.

Что-то вроде:

Dictionary<int, int> values; 

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

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

, а затем, чтобы получить доступ к нему:

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

Попробуйте использовать дженерики:

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

и т.д.

Затем поиска [22] вернет значение 3. Я принесу gest, используя набор циклов для создания ваших «диапазонов». С помощью этого метода вам гарантируется время доступа O (1).

+1

Вы серьезно полагаете, что он добавляет различные значения в словарь для каждого целостного значения в своих диапазонах? –

+0

Да. Для небольшого количества диапазонов это может быть то, что ищет OP. У вас есть лучшее решение? Если да, то пост. –

+0

@Charlie: Мне не нужно отвечать за ответы, которые уже были отправлены dtb и agileguy. –

0

Для будущего расширения я бы сделал 2 словаря. Только в случае, если эти цены изменяются так

dictionary<string,dictionary<int,int>> 

или просто использовать пользовательские классы строка будет статические строками, такие как низкий мед, высоким, то вы можете изменить диапазоны в вашем Еогеаспе initilixing начальных значений

1

Хорошо - это функция цели. Все приведенные выше решения хорошо работают, предполагая, что любой заданный диапазон представляет собой небольшое число целых чисел. В противном случае вы можете использовать любую функцию математики реального мира, чтобы определить вашу группу. Например, для приведенного примера ваша функция ответа будет x% 10 + 1; Это будет работать намного быстрее, чем словарь.

0

Одним из решений было бы использовать простой список, где каждая позиция в списке представляет собой другую позицию, которую вы просматриваете. В коде это может выглядеть примерно так (при условии, что все номера позиций являются последовательными):

** Примечание. Я действительно не запускаю этот код, чтобы убедиться, что он работает как есть ... вам также может потребоваться реализовать IEqualityComparer на Range для того, чтобы IndexOf операции, чтобы вернуть правильное положение:

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

Это, вероятно, довольно очевидно, но, чтобы избежать путаницы, вот что Range класс может выглядеть следующим образом:

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

если есть прямая корреляция между диапазоном сигнала и позицией, то используйте то, что предложил @agileguy.

Если позиции распределены Некоммерческие линейно по силе сигнала, то один из способов будет:

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

Если вы хотите использовать словарь, вам нужно по крайней мере, какой-то особый тип ключа, чтобы иметь дело с диапазонами. KeyType может быть абстрактным и двумя производными типами KeyTypeRange (int int) и KEyTypeSearch (int). Для сравнения KeyTypeSearch с 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)); 

В нем показано возможное решение для использования различных ключей поиска и ключевых слов в словарях. Но для этой проблемы это кажется Overkill. Эта проблема решается лучше всего с помощью решения BinarySearch.

+0

Хорошо упомянуть об этом подходе. Я предпочитаю бинарный поиск, но полезно указать KeyTypeRange вместо загрузки словаря со всеми возможными значениями, как было упомянуто ранее. – Steve

+0

@Thomas: Звучит интересно. Можете ли вы рассказать о своей идее? 'Словарь ' реализован как хеш-таблица. Как вы реализуете 'GetHashCode'' KeyTypeRange' и 'KeyTypeSearch', так что' new KeyTypeSearch (15) 'дает' новый KeyTypeRange (1,10) '? – dtb

+0

На самом деле вы не можете использовать словарь , вы должны использовать SortedDictionary , потому что для этой проблемы невозможно предоставить функцию хэша. Сортированные словарные ключи сравниваются с помощью int IComparer . Компиляция (T x, T y), которую легко реализовать. –

Смежные вопросы