Сортировать результаты поиска из текстового файла в список - PullRequest
1 голос
/ 15 июля 2010

у меня есть текстовое поле, в которое пользователь вводит строку.Строка будет выглядеть примерно так: G32:04:20:40

Тогда пользователь нажимает кнопку поиска.Затем программа должна открыть текстовый файл и найти «ближайшие» пять строк к той, которую они ввели, и отобразить их в списке.

Я определю «ближайшую строку» столько, сколько смогу (скорее всего,используя очень длинный сложный пример).

Данные, содержащиеся в текстовом файле, выглядят так:

G32:63:58:11 JG01
G32:86:98:30 JG01
G33:50:05:11 JG06
G33:03:84:12 JG05
G34:45:58:11 JG07
G35:45:20:41 JG01
G35:58:20:21 JG03

Так что, если пользователь вводит строку:

G33:89:03:20

Пять ближайших результатов должны отображаться в окне списка следующим образом:

G33:50:05:11 JG06
G33:03:84:12 JG05
G32:86:98:30 JG01
G32:63:58:11 JG01
G34:45:58:11 JG07

В этой точке, вероятно, следует указать, что строки являются координатами, а значение после "JG" представляетзначение чего-то в этой координате.

Способ, которым я добрался до этих 5, состоит в том, чтобы пройти строку по частям.Итак, пользователь набрал «G33», поэтому я нахожу все те, у кого G33 в начале - если их нет, то я нахожу ближайший к G33.Тогда это было «89», так что я нахожу все те, где следующая часть - «89», если их нет, то ближе всего к 89, тем лучше и т. Д.

Что мне нужно знать, так это какидти делать это?Я построил визуальные компоненты, и у меня также есть код, который имеет дело с подобными вещами, но когда дело доходит до этого, я действительно озадачен.Как вы, наверное, уже сейчас знаете, я довольно новичок в C #, но я учусь:)

РЕДАКТИРОВАТЬ: Поиск кода

private void btnSearch_Click(object sender, EventArgs e)
        {
            lstResult.Items.Clear();

            if (txtSearch.Text == String.Empty)
            {
                MessageBox.Show("The textbox is empty, there is nothing to search.",
                    "Textbox empty", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                this.CheckFormatting();
            }

        }

        private long GetIndexForCoord(string coord)
        {
            // gets out a numerical value for each coordinate to make it easier to compare
            Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d");
            string cleaned = m_regex.Match(coord).Value;
            cleaned = cleaned.Replace(':', '0');
            return Convert.ToInt64(cleaned);
        }

        private List<string> GetResults(string coord)
        {
            // gets out the 5 closest coordinates
            long index = GetIndexForCoord(coord);

            // First find the 5 closest indexes to the one we're looking for
            List<long> found = new List<long>();
            while (found.Count < 5)
            {
                long closest = long.MaxValue;
                long closestAbs = long.MaxValue;
                foreach (long i in m_indexes)
                {
                    if (!found.Contains(i))
                    {
                        long absIndex = Math.Abs(index - i);
                        if (absIndex < closestAbs)
                        {
                            closest = i;
                            closestAbs = absIndex;
                        }
                    }
                }
                if (closest != long.MaxValue)
                {
                    found.Add(closest);
                }
            }

            // Then use those indexes to get the coordinates from the dictionary
            List<string> s = new List<string>();
            foreach (long i in found)
            {
                s.Add(m_dic[i]);
            }
            return s;
        }

        private void CheckFormatting()
        {
            StringReader objReader = new StringReader(txtSearch.Text);

            bool FlagCheck = true;

                if (!Regex.IsMatch(txtSearch.Text,
                    "G3[0-9]{1}:[0-9]{2}:[0-9]{2}:[0-9]{2}"))
                {
                    FlagCheck = false;
                }

            if (FlagCheck == true)
            {
                this.CheckAndPopulate();
            }
            else
            {
                MessageBox.Show("Your search coordinates are not formatted correctly.",
                       "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void CheckAndPopulate()
        {
            StreamReader objReader = new StreamReader("Jumpgate List.JG");
            List<String> v = new List<String>();
            do
            {
                v.Add(objReader.ReadLine());
            }
            while (objReader.Peek() != -1);

            objReader.Close();

            foreach (string c in v)
            {
                long index = GetIndexForCoord(c);
                m_dic.Add(index, c);
                m_indexes.Add(index);
            }

            List<string> results = GetResults(txtSearch.Text);
            foreach (string c in results)
            {
                lstResult.Items.Add(c);
            }
        }

1 Ответ

3 голосов
/ 16 июля 2010

Редактировать: Добавлен предлагаемый код для чтения в файле.А также пояснение в конце.
Edit2: добавлено, если проверяется добавление в словарь / список для обработки дубликатов.

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

Я предположил, что буква в начале всегда G и чтовсе 4 части координат всегда состоят из двух цифр.

Добавьте следующие 2 в ваш класс / форму:

    Dictionary<long, string> m_dic = new Dictionary<long, string>();
    List<long> m_indexes = new List<long>();

Затем инициализируйте их следующим кодом (я предположил, что выВы уже прочитали все координаты в строковый массив с именем v (по одной координате на элемент):

foreach (string c in v)
{
    long index = GetIndexForCoord(c);
    if(!m_dic.ContainsKey(index))
    {
        m_dic.Add(index, c);
        m_indexes.Add(index);
    }
}

Затем добавьте следующие 2 метода:

// gets out a numerical value for each coordinate to make it easier to compare
private long GetIndexForCoord(string coord)
{
    Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d");
    string cleaned = m_regex.Match(coord).Value;
    cleaned = cleaned.Replace(':', '0');
    return Convert.ToInt64(cleaned);
}
// gets out the 5 closest coordinates
private List<string> GetResults(string coord)
{
    long index = GetIndexForCoord(coord);

    // First find the 5 closest indexes to the one we're looking for
    List<long> found = new List<long>();
    while (found.Count < 5)
    {
            long closest = long.MaxValue;
            long closestAbs = long.MaxValue;
            foreach (long i in m_indexes)
            {
                if (!found.Contains(i))
                {
                    long absIndex = Math.Abs(index - i);
                    if (absIndex < closestAbs)
                    {
                        closest = i;
                        closestAbs = absIndex;
                    }
                }
            }
            if (closest != long.MaxValue)
            {
                found.Add(closest);
            }
    }

    // Then use those indexes to get the coordinates from the dictionary
    List<string> s = new List<string>();
    foreach (long i in found)
    {
        s.Add(m_dic[i]);
    }
    return s;
}

И, наконец,когда пользователь вводит данные, которые вы отправляете в эти данные в метод, как:

List<string> results  = GetResults(lookingFor);

Затем вы можете использовать результаты для заполнения списка.

Код работает путем преобразования каждой координаты вчисловое значение, называемое индексом (поскольку с ним легче работать), а затем оно добавляет все координаты в словарь с индексом в качестве ключа.
Когда он ищет ближайшие координаты, он сравнивает разностьЗначение в диапазоне между индексом, который вы ищете, и каждым из ранее сохраненных индексов, чтобы найти 5 самых близких (он использует метод Math.Abs, чтобы он мог получить разницу, не беспокоясь о отрицательных числах).Это довольно неэффективно, поскольку он проходит по каждому значению один раз для каждой координаты, которую вы хотите найти (поэтому, если ваш список содержит 1000 координат, и вы хотите найти 5 ближайших, он пройдет внутренний цикл 5000 раз, я бы предположил, чтовероятно, можно было бы сократить его до 1000 раз, улучшив код, я предлагаю посмотреть вики-ссылку, расположенную близко к началу этого ответа, для лучшего алгоритма).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...