Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Поиск в векторе


Автор: artsb 2.12.2007, 23:50
Уже, наверное, все видели эту структуру   smile :
Код

struct gr{
AnsiString name;
AnsiString www;
AnsiString inf;
};
vector<gr> grp;

Нужно организовать поиск слова или сочетания слов. Например, пользователь выбирает один из трёх вариантов в ComboBox'е (3 - количество переменных в структуре). Если выбран первый вариант, поиск будет проходить по переменным name в векторе. Но в ней может храниться предложение.

Уф-ф-ф, надеюсь понятно объяснил. smile

Автор: Diamido 3.12.2007, 08:48
Если выбрана 1-я галочка только в name идёт поиск, 1-я и 2-я в name и www

Самый тривиальный способ решения:

1. Есть функция для поиска строки в подстроке, возвращает индекс где находиться первый символ искомой строки. (не помню как она называется str* вродебы)
2. Просто пишешь процедуру которая анализирует выбраные галочки и ищет по каждой строке, если найдено хоть одно совпадение возвращает индекс записи в струкруре.
3. Потов выводишь найденую структуру куда тебе надо и продолжаешь поиск если надо. 

Автор: artsb 3.12.2007, 09:59
Попробую объяснить ещё раз:
В ComboBox'е юзверь выбирает один из вариантов, а в Edit вводит текст. Допустим он выбрал первый, тогда поиск должен идти по name. Как только будет найдено совпадение, поиск останавливается, а мне нужно получить индекс текущего элемента вектора.
В принципе, всё это я смогу сделать, вопрос в следующем:
Как сделать поиск если в Edit может быть введено слово или сочетание слов и в name может быть слово, а может предложение?

Автор: volvo877 3.12.2007, 12:56
artsb, возможно это решается гораздо проще, но в свое время я реализовывал подобный поиск через так называемую "Levenshtein distance" - коэффициент "похожести" двух строк... Если похожесть очень высока, то строка считается  найденной, и поиск останавливается...

Автор: xvr 3.12.2007, 15:53
Цитата(artsb @ 3.12.2007,  09:59)
Попробую объяснить ещё раз:
В ComboBox'е юзверь выбирает один из вариантов, а в Edit вводит текст. Допустим он выбрал первый, тогда поиск должен идти по name. Как только будет найдено совпадение, поиск останавливается, а мне нужно получить индекс текущего элемента вектора.
В принципе, всё это я смогу сделать, вопрос в следующем:
Как сделать поиск если в Edit может быть введено слово или сочетание слов и в name может быть слово, а может предложение?

Делишь name и Edit на набор слов (например функцией strtok или через TStringList), затем сохраняешь их в map<AnsiString,int>, добавляя в map 1 для name и 2 для Edit. Если получится элемент с 3 - искомое пересечение найдено.
Код

map<AnsiString,int> acc;
bool add_tokens(AnsiString str, int val)
{
 for(char* p=strtok(str.c_str()," ");p;p=strtok(NULL," "))
  {
    if ( (acc[p]|=val) == 3) return true;
  }
 return false;
}

int find_by_name()
{
 for( <all names> )
  {
   acc.clear();
   add_tokens(Edit1->Text,1);
   if (add_tokens(name,2)) return <current index>;
  }
 return <not found>; 
}

Но быстрее будет вариант с set<AnsiString> куда будут складываться слова из Edit (один раз) и затем проверяться на принадлежность этому множеству слова из name

Автор: artsb 3.12.2007, 19:21
А если так?
Код

int find(int flag)
{
int n=0;
AnsiString str;
switch (flag)
{
     case 1: str=grp.name; break;
     case 2: str=grp.www; break;
     case 3: str=grp.inf; break;
}
                    for(char* p=strtok(str," ");p;p=strtok(NULL," "))
                    {
                            if ( p == Form1->Edit1->Text) return n;
                            else n++;
                    }
return -1;
}

Так будет работать? А то я не проверял.

Автор: xvr 3.12.2007, 19:28
Цитата(artsb @ 3.12.2007,  19:21)
А если так?
Код

int find(int flag)
{
int n=0;
AnsiString str;
switch (flag)
{
     case 1: str=grp.name; break;
     case 2: str=grp.www; break;
     case 3: str=grp.inf; break;
}
                    for(char* p=strtok(str," ");p;p=strtok(NULL," "))
                    {
                            if ( p == Form1->Edit1->Text) return n;
                            else n++;
                    }
return -1;
}

Так будет работать? А то я не проверял.

Будет, но данные в поле ввода (Edit1) будут рассматриваться как слово, а не как набор слов. Кроме того, если в этих данных будет хоть один пробел, то ничего найдено не будет (вообще)

Автор: artsb 3.12.2007, 21:37
xvr ты не мог бы отредактировать мой пример так, чтобы данные в Edit1  рассматривались как набор слов, если их там несколько.
Как можно из строки удалить определённый символ? Например, из "Мама мыла раму" удалить все 'м'.

Автор: xvr 3.12.2007, 21:48
Цитата(artsb @ 3.12.2007,  21:37)
xvr ты не мог бы отредактировать мой пример так, чтобы данные в Edit1  рассматривались как набор слов, если их там несколько.

Мог бы


Код

int find(int flag)
{
 int n=0;
 AnsiString str;
 switch (flag)
  {
     case 1: str=grp.name; break;
     case 2: str=grp.www; break;
     case 3: str=grp.inf; break;
  }

 set<AnsiString> active_set;
 for(char* p=strtok(Form1->Edit1->Text.c_str()," ");p;p=strtok(NULL," "))
  active_set.insert(p);

 for(char* p=strtok(str.c_str()," ");p;p=strtok(NULL," "))
   {
     if ( active_set.count(p)!=0 ) return n;
     else n++;
   }
 return -1;
}

Я правда не совсем понял зачем нужен был параметр flag, и зачем ты возвращал номер совпавшего слова (он кому то нужен)?

Цитата

Как можно из строки удалить определённый символ? Например, из "Мама мыла раму" удалить все 'м'.


Код

str=AnsiReplaceStr(str,"м","");


Автор: artsb 3.12.2007, 22:52
Спасибо. У меня пара вопросов:

Цитата(xvr @  3.12.2007,  21:48 Найти цитируемый пост)
 set<AnsiString> active_set;
 for(char* p=strtok(Form1->Edit1->Text.c_str()," ");p;p=strtok(NULL," "))
  active_set.insert(p);

set - это же множество, в котором каждый элемент уникален. Если вдруг юзверь введёт два одинаковых слова, не будет ошибки?


Цитата(xvr @  3.12.2007,  21:48 Найти цитируемый пост)
if ( active_set.count(p)!=0 )

Не пойму, что здесь происходит. Count - это ж вроде количество? И почему ты сравниваешь с нулём? Каков результат операции?



Цитата(xvr @  3.12.2007,  21:48 Найти цитируемый пост)
Я правда не совсем понял зачем нужен был параметр flag, и зачем ты возвращал номер совпавшего слова (он кому то нужен)?

Параметр flag нужен, чтобы передать в функцию какой вариант выбрал юзверь (в ComboBox'е три строки, если выбрана первая, то flag=1).
Возвращаемое значение нужно для установки индекса в ListBox, что бы сделать строку с этим индексом активной.

За ответ на второй вопрос спасибо. Я так поня, что там 'м' меняется на ''.

Автор: xvr 4.12.2007, 15:19
Цитата(artsb @ 3.12.2007,  22:52)
Спасибо. У меня пара вопросов:

Цитата(xvr @  3.12.2007,  21:48 Найти цитируемый пост)
 set<AnsiString> active_set;
 for(char* p=strtok(Form1->Edit1->Text.c_str()," ");p;p=strtok(NULL," "))
  active_set.insert(p);

set - это же множество, в котором каждый элемент уникален. Если вдруг юзверь введёт два одинаковых слова, не будет ошибки?


Не будет.

Цитата

Цитата(xvr @  3.12.2007,  21:48 Найти цитируемый пост)
if ( active_set.count(p)!=0 )

Не пойму, что здесь происходит. Count - это ж вроде количество? И почему ты сравниваешь с нулём? Каков результат операции?

count возвращает количество элементов, заданных параметром, в set. Оно может быть 0 - set не содержит этого элемента, или 1 - set содержит данный элемент

Цитата

Возвращаемое значение нужно для установки индекса в ListBox, что бы сделать строку с этим индексом активной.

Возвращается номер слова в фразе, а не номер элемента в ListBox'е (он там вообще не фигурирует)

Автор: artsb 4.12.2007, 20:38
Всё понятно спасибо. Надо будет потом чуть-чуть доделать, ведь у меня поиск в векторе, а не в одной строке.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)