Aeryes
Aeryes

Reputation: 681

Why is my search function not working as expected and how do I fix it?

I am trying to make a comparison search function that can compare two strings together based on chars. For example:

Input: "ca" Struct vector contents under last name fields(sorted vector)(index/value): 0/"cars", 1/"roads" Result: "Name Found at index 0 - cars"

I want users to be able to use any number of chars. The program should then compare the provided search criteria to the content of the vector and return the index of any matches.

So far I have tried to implement this alogorithm without any success, here is my code so far. Also I am pretty new to C++.

// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string name) {

    int loc = -1;
    int counter = 0;
    int index = 0;

    //when loc is no longer -1, that means the person has been found

    for (int i = 0; i < people.size(); i++)

        for(int k = 0; k < name.length(); k++) {

            std::cout << name[k-1] << std::endl;
            std::cout << people[i].lastname[k-1] << std::endl;
            std::cout << counter << std::endl;
            std::cout << "" << std::endl;

            if(name[k-1] == people[i].lastname[k-1]) {

                counter++;

            }

            if(counter == name.length()) {

                loc = i;
                break;

            }
        }

        //if (people[i].lastname.compare(name) == 0)

            //loc = i;

    return loc;

}

Here is what I get in my console, I am using cout to debug:

What is player 1 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
hello sunshine
What is player 2 information (F/L/DOB (DD/MM/YYY)), Seperate using a space):
good bye
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;

3
Array Sorted!!!
Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;

4
Player 1: good bye
Player 2: hello sunshine

Pick from the available options:
1 - Input Data:
2 - Display Original Data:
3 - Sort Data:
4 - Display Sorted Data:
5 - Search By Last Name:
6 - Exit The Program;

5
Enter the name to search:
bye
b
b
0

y
y
1

e
e
2

b
s
3

y
u
4

e
n
4

Player Found:  good bye
Enter the name to search:
by
y
b
0

y
s
1

Player Found:  good bye
Enter the name to search:
b
The player was not found, try again.
Enter the name to search:
sun
u
b
0

n
y
1

u
s
1

Player Found:  hello sunshine
Enter the name to search:
sunshine
u
b
0

n
y
1

s
e
1

h

1

i
h
1

n
i
1

e
n
1

u
s
1

n
u
2

s
n
2

h
s
2

i
h
2

n
i
2

e
n
2

The player was not found, try again.
Enter the name to search:

EDIT: As you can see from my console output the code is returning true comparisons when it shouldn't be doing so. An example is the last comparison of is (e == n). The answer should be false but it keeps returning true.

After using code suggested in the comments I still cant get my code to work as expected and get the following errors:

    ||=== Build file: "no target" in "no project" (compiler: unknown) ===|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'int main()':|
E:\Coding\Cplus_work\assignmentseven.cpp|68|warning: NULL used in arithmetic [-Wpointer-arith]|
E:\Coding\Cplus_work\assignmentseven.cpp|158|warning: NULL used in arithmetic [-Wpointer-arith]|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h||In instantiation of 'bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]':|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|120|required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|161|required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = __gnu_cxx::__ops::_Iter_pred<searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)> >]'|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\stl_algo.h|3930|required from '_IIter std::find_if(_IIter, _IIter, _Predicate) [with _IIter = __gnu_cxx::__normal_iterator<playerdata*, std::vector<playerdata> >; _Predicate = searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>]'|
E:\Coding\Cplus_work\assignmentseven.cpp|35|required from here|
c:\mingw\lib\gcc\mingw32\8.2.0\include\c++\bits\predefined_ops.h|283|error: no match for call to '(searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>) (playerdata&)'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note: candidate: 'searchArray(std::vector<playerdata>&, std::__cxx11::string&)::<lambda(std::__cxx11::string&)>'|
E:\Coding\Cplus_work\assignmentseven.cpp|33|note:   no known conversion for argument 1 from 'playerdata' to 'std::__cxx11::string&' {aka 'std::__cxx11::basic_string<char>&'}|
E:\Coding\Cplus_work\assignmentseven.cpp||In function 'bool sortArray(const playerdata&, const playerdata&)':|
E:\Coding\Cplus_work\assignmentseven.cpp|28|warning: control reaches end of non-void function [-Wreturn-type]|
||=== Build failed: 1 error(s), 8 warning(s) (0 minute(s), 0 second(s)) ===|

Exact code I used:

// Function for searching through an array for a string value.
int searchArray(std::vector<playerdata> (&people), std::string (&name))
{
    auto it = std::find_if(people.begin(), people.end(), [&name](std::string& person){
        return person.find(name) != std::string::npos;
    });

    if(it != people.end()) {

        return std::distance(people.begin(), it);

    } else {

        return -1;

    }
}

Upvotes: 0

Views: 541

Answers (2)

Burak Karasoy
Burak Karasoy

Reputation: 1690

  1. First of all your approach to solution is correct but needs some improvement.
  2. I assumed that you don`t want to solve it using regular expression or a template c++ function which would be better way
  3. You may have a misunderstanding about break statement which affects only the loop it is written in break
  4. I've explained missing points and required improvements in comment
    lines
  5. Since you didn`t specify all details I had to assume them.

`

SearchArray(std::vector<playerdata>& people, const std::string& keyWord) 
{

  int loc = -1;

  // Use a better variable name to explain its purpose instead of `i`
  // so you and other people like us can understand its meaning much faster
  for (int vectorIndex = 0; vectorIndex < people.size(); vectorIndex++)
  {
    // if length of the name is bigger than a lastname it can`t be a match so just continue
    if (keyWord.length() > people[vectorIndex].lastname.length())
    {
        continue;
    }

    int counter = 0;
    int charIndexKeyWord = 0;
    // Use a better variable name to explain its purpose instead of `k`
    for (int charIndexIarget = 0; charIndexIarget < people[vectorIndex].lastname.length(); charIndexIarget++)
    {           
        // Your for loop starts from 0 but you're trying to use [k-1] in your code
        // you shouldn't do that, because in the first iteration of the loop it will indicate -1 [k-1]
        // but it starts with 0, 

        //std::cout << keyWord[charIndexKeyWord] << std::endl;
        //std::cout << people[vectorIndex].lastname[charIndexIarget] << std::endl;
        //std::cout << counter << std::endl;
        //std::cout << "" << std::endl;

        // This is part of your code which needs improvment
        if (keyWord[charIndexKeyWord] == people[vectorIndex].lastname[charIndexIarget]) 
        {
            counter++; 
            charIndexKeyWord++;
        }
        else
        {
            // If you keep your code as it is, it will may also consider matches like susnhine `sun` because
            // so you need to make some improvements to get rid of it.
            // if you have already founded a match but next word is not a match then you need to start looking from  the beginning
            if (counter != 0)
            {
                counter = 0;
                charIndexKeyWord = 0;                   
            }               
        }

        if (counter == keyWord.length())
        {

            loc = vectorIndex;
        }
    }

    if (loc != -1)
    {
        break;
    }

}

return loc;

}

Upvotes: 0

serkan.tuerker
serkan.tuerker

Reputation: 1821

Probably the main problem is that you are trying to access name[k-1] and lastname[k-1], when k=0, which results in UB.

Before continuing with your work, start learning the STL algorithms. With that in mind, your task becomes trivial using only find_if and std::string::find:

#include <algorithm>
#include <iostream>
#include <vector>
#include <string>

struct playerdata
{
    std::string lastname;

    playerdata(std::string lastname) :
        lastname(std::move(lastname))
    {
    }
};

int searchArray(std::vector<playerdata>& people, const std::string& name) 
{
    auto it = std::find_if(people.cbegin(), people.cend(), [&name](const playerdata& player){
        return player.lastname.find(name) != std::string::npos;
    });

    if(it != people.end())
        return std::distance(people.cbegin(), it);
    else 
        return -1;
}

}

LIVE DEMO

Upvotes: 2

Related Questions