How to implement find_if and remove_if

Hello and Good morning.
Here is my code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

struct Person
{
        string Name;
        string ID;
};

class mainClass
{
        private :
                vector <Person> Vector;
        
        public :
                mainClass() { }
                void storeVector();
                void displayVector();
                void findID();
                void removeID();
};

void mainClass :: storeVector()
{
        Person Obj1;
        Obj1.Name = "Tapas";
        Obj1.ID = "1";
        Vector.push_back(Obj1);
        
        Person Obj2;
        Obj2.Name = "Ashok";
        Obj2.ID = "2";
        Vector.push_back(Obj2);
        
        Person Obj3;
        Obj3.Name = "Arnab";
        Obj3.ID = "3";
        Vector.push_back(Obj3);
        
        Person Obj4;
        Obj4.Name = "Sayantan";
        Obj4.ID = "4";
        Vector.push_back(Obj4);
        
        Person Obj5;
        Obj5.Name = "Mrinal";
        Obj5.ID = "5";
        Vector.push_back(Obj5);
}

void mainClass :: displayVector()
{
        for (vector <Person> :: iterator it = Vector.begin(); it != Vector.end(); it++)
        {
                cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
        }
}

void mainClass :: findID()
{
        string ID;
        
        cout << "  Enter the ID to find : ";
        cin >> ID;
        
        vector <Person> :: iterator it;
        
        for (it = Vector.begin(); it != Vector.end(); it++)
        {
                if (ID == it->ID)
                {
                        break;
                }
        }
        
        if (it != Vector.end())
        {
                cout << "  Specified ID found." << endl;
                cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
        }
        else
        {
                cout << "  Specified ID not found." << endl;    
        }
}

void mainClass :: removeID()
{
        string ID;
        
        cout << "  Enter the ID to remove : ";
        cin >> ID;
        
        vector <Person> :: iterator it;
        
        for (it = Vector.begin(); it != Vector.end(); it++)
        {
                if (ID == it->ID)
                {
                        break;
                }
        }
        
        if (it != Vector.end())
        {
                cout << "  Specified ID found." << endl;
                cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
                Vector.erase(it);
        }
        else
        {
                cout << "  Specified ID not found." << endl;    
        }
}

int main()
{
        mainClass Obj;
        
        Obj.storeVector();
        Obj.displayVector();
        Obj.findID();
        Obj.removeID();
        Obj.displayVector();
                
        return 0;
}

This code is okay and gives desired output, but I want to implement findID() and removeID() function using find/find_if and remove_if function of algorithm header. Is it possible? If possible, then how can I implement it? Please help.
For the find, just replace the loop that searches for ID with it = std::find(Vector.begin(), Vector.end(), ID)

Remove case will look a bit funnier. For the remove_if, you have to use the erase(remove) idiom. ::std::remove alone cannot change the vector, as it gets only passed iterators and there is no way for a C++ iterator to delete anything from the list it came from (nor how to get back to the list it was obtained from).

So you use the vector's erase function together with remove: Vector.erase(remove(Vector.begin(), Vector.end(), ID)), Vector.end());


Ciao, Imi.
I have solve it in the following manner. Is it okay?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <functional>
#include <iterator>

using namespace std;

struct Person
{

	string Name;
	string ID;
};

class mainClass
{
	private :
		vector <Person> Vector;
	
	public :
		mainClass() { }
		void storeVector();
		void displayVector();
		void findID();
		void removeID();
		
		friend ostream & operator << (ostream &, const Person &);
};

struct IDnumber : public binary_function <Person, string, bool> 
{
	bool operator () ( const Person &Obj, const string &ID ) const 
	{
    		return (Obj.ID == ID);
	}
};

ostream & operator << (ostream &stream, const Person &Obj)
{
	return stream << "  Name : " << Obj.Name << ", ID : " << Obj.ID;
}

void mainClass :: storeVector()
{
	Person Obj1;
	Obj1.Name = "Tapas";
	Obj1.ID = "1";
	Vector.push_back(Obj1);
	
	Person Obj2;
	Obj2.Name = "Ashok";
	Obj2.ID = "2";
	Vector.push_back(Obj2);
	
	Person Obj3;
	Obj3.Name = "Arnab";
	Obj3.ID = "3";
	Vector.push_back(Obj3);
	
	Person Obj4;
	Obj4.Name = "Sayantan";
	Obj4.ID = "4";
	Vector.push_back(Obj4);
	
	Person Obj5;
	Obj5.Name = "Mrinal";
	Obj5.ID = "5";
	Vector.push_back(Obj5);
}

void mainClass :: displayVector()
{	
	copy(Vector.begin(), Vector.end(), ostream_iterator <Person> (cout, "\n"));
}

void mainClass :: findID()
{
	string ID;
	
	cout << endl;
	cout << "  Enter the ID to find : ";
	cin >> ID;
	
	vector <Person> :: iterator it;
	
	it = find_if(Vector.begin(), Vector.end(), bind2nd(IDnumber(), ID));
	
	if (it != Vector.end())
	{
		cout << "  Specified ID found." << endl;
		cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
	}
	else
	{
		cout << "  Specified ID not found." << endl;	
	}
}

void mainClass :: removeID()
{
	string ID;
	
	cout << endl;
	cout << "  Enter the ID to remove : ";
	cin >> ID;
	
	vector <Person> :: iterator it;
	
	it = find_if(Vector.begin(), Vector.end(), bind2nd(IDnumber(), ID));
	
	if (it != Vector.end())
	{
		cout << "  Specified ID found." << endl;
		cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
		Vector.erase(it);
		cout << "  Data successfully deleted." << endl << endl;
	}
	else
	{
		cout << "  Specified ID not found." << endl;	
	}
}

int main()
{
	mainClass Obj;
	
	Obj.storeVector();
	Obj.displayVector();
	Obj.findID();
	Obj.removeID();
	Obj.displayVector();
		
	return 0;
}
Well, I don't see the need for IDNumber and find_if. You can just use "find". But in theory it seems ok like this. However, removeID only removes one ID - if you have multiple ID's with the same value, it doesn't work.. (hm.. while writing this, I recognize that "ID" should be unique anyway.. ;)

Ciao, Imi.
Actually I am writing a student database, this is a large program compare to this one. In that program I am using find_if, and this code is the trial one. You are right, ID is the primary key, and I am maintaining the uniqueness of ID. If want to see that code I can post it here after completion.
If your compiler already support them, you may also use lambda functions. They work like a charm together with find_if (http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions):

 
it = find_if(Vector.begin(), Vector.end(), [&ID](const Person& p)->bool{return p.ID == ID;} );


Ciao, Imi.
I am getting these error:

tapas@My-Child:~/Programming/Student Database$ g++ "Student Database 1.cpp" -o "Student Database 1.o"
Student Database 1.cpp: In member function ‘__gnu_cxx::__normal_iterator<Student*, std::vector<Student, std::allocator<Student> > > MainClass::isIDPresent(std::string)’:
Student Database 1.cpp:56: error: expected primary-expression before ‘[’ token
Student Database 1.cpp:56: error: expected primary-expression before ‘const’
Student Database 1.cpp:56: error: expected unqualified-id before ‘bool’

Is there any header needed?
I am in Ubuntu.
Last edited on
Is that error from your second post? What did you try to compile? I was not clear about that.
I think he tried imi's solution but does not have a compiler that implements the proposed C++0x.
Your display function was not working for me the second time that it was called; possibly because there was no manual stream flush. I changed that so that I could run your program and I wanted to show you how to simplify your function that removes an element.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void mainClass :: displayVector()
{	
    //copy(Vector.begin(), Vector.end(), ostream_iterator <Person> (cout, "\n"));
    for(vector<Person>::iterator pos = Vector.begin(); pos != Vector.end(); pos++)
	std::cout << *pos << std::endl;
}

void mainClass :: removeID()
{
    string ID;

    cout << endl;
    cout << "  Enter the ID to remove : ";
    cin >> ID;

    //vector <Person> :: iterator it;

    //it = find_if(Vector.begin(), Vector.end(), bind2nd(IDnumber(), ID));
    Vector.erase(remove_if(Vector.begin(), Vector.end(), bind2nd(IDnumber(), ID)),
	         Vector.end());
		/*if (it != Vector.end())
	{
		cout << "  Specified ID found." << endl;
		cout << "  Name : " << it->Name << ", ID : " << it->ID << endl;
		Vector.erase(it);
		cout << "  Data successfully deleted." << endl << endl;
	}
	else
	{
		cout << "  Specified ID not found." << endl;	
		}*/
}
Thank you for your reply. Actually I am studying some advance level programming in c++, that is why I am using find_if, remove_if, and copy function. I am doing programming in my Ubuntu. But don't understand why the display function is not working for second time, it works fine in my machine.
I've never seen it done that way before but I don't see a manual flush at all. The following function may or may not result in the phrase being printed to the console. There is no flush.
std::cout << "hello world\n";

Whenever you fail to implement a manual flush you can't control when and if the data is ever printed to the console. I have a different compiler and run-time environment.
Tapas Bose wrote:

But don't understand why the display function is not working for second time, it works fine in my machine.

That's what the difference of cout << endl and cout << "\n" is. endl also flushes the stream, whereas \n does not. Not all implementation do buffer cout at all (it seems that yours does no buffering). But for example the one shipped with Microsoft VisualStudio does (http://support.microsoft.com/kb/94227).


Just think of cout << std::endl as if it were cout << "\n" << std::flush.
For more, see http://www.cplusplus.com/reference/iostream/manipulators/endl

Ciao, Imi.
Okay. understand.
Topic archived. No new replies allowed.