Searching and finding multiple instances of same key in multimap?

I would like to use a key to search and find multiple instances of the same key in multimap.

Here's what I have so far:

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
	// enum to make characters easy to identify
	enum struct characterType
	{
		object,
		humanplayer,
		enemy,
		editing,
		null
	};

	// struct to store sizes
	struct objSizeType
	{
		int ybottom;
		int xleft;
		int ytop;
		int xright;
	};


	// make storage container
	std::multimap<characterType, objSizeType> objSizeMap;

	// make temp struct to hold data that will be stored in objSizeMap
	objSizeType objSize;
	
	
	// humanplayer
	objSize.ybottom	= 0;
	objSize.xleft	= 0;
	objSize.ytop		= -2;
	objSize.xright	= 2;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::humanplayer, objSize));
	
	objSize.ybottom	= -3;
	objSize.xleft	= 1;
	objSize.ytop		= -3;
	objSize.xright	= 1;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::humanplayer, objSize));

	
	// object
	objSize.ybottom	= 0;
	objSize.xleft	= 0;
	objSize.ytop 	= 0;
	objSize.xright 	= 0;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::object, objSize));
	
	
	// enemy
	objSize.ybottom 	= -3;
	objSize.xleft 	= 1;
	objSize.ytop 	= -3;
	objSize.xright 	= 1;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::enemy, objSize));
	
	objSize.ybottom	= 0;
	objSize.xleft	= 0;
	objSize.ytop 	= -2;
	objSize.xright 	= 2;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::enemy, objSize));

	objSize.ybottom	= 1;
	objSize.xleft	= -3;
	objSize.ytop 	= 1;
	objSize.xright 	= 5;
	objSizeMap.insert(std::pair<characterType, objSizeType>(characterType::enemy, objSize));


	// so i've got this far and works fine; info is stored and can be displayed...
	// now i'd like to search and capture multiple instances of lets say, 'enemy'

	// make temp storage of struct
	objSizeType tempMap;
	
	// store found struct to use in code later
	tempMap = objSizeMap.find(characterType::enemy)->second;


The code works but it only find one instance of enemy, when infact there are 3 instances. If anyone has any suggestions it would be appreciated. I have searched google and looked in a couple of C++ books and no mention of this.

You can use the function equal_range.
http://en.cppreference.com/w/cpp/container/multimap/equal_range

1
2
3
4
5
6
std::pair<std::multimap<characterType, objSizeType>::iterator, std::multimap<characterType, objSizeType>::iterator> range = objSizeMap.equal_range(characterType::enemy);

for (std::multimap<characterType, objSizeType>::iterator it = range.first; it != range.second; ++it)
{
	// do something with *it.
}



You can make the insertion lines shorter by using std::make_pair.
objSizeMap.insert(std::make_pair(characterType::humanplayer, objSize));

and instead of using the very long names for the iterators you can create an alternative name for them by using typedef.
1
2
3
4
5
6
7
typedef std::multimap<characterType, objSizeType>::iterator SizeMapIter;
std::pair<SizeMapIter, SizeMapIter>::iterator> range = objSizeMap.equal_range(characterType::enemy);

for (SizeMapIter it = range.first; it != range.second; ++it)
{
	// do something with *it.
}


In C++11 you can make it even shorter by using the {}-syntax
objSizeMap.insert({characterType::humanplayer, objSize});
or even better, by using emplace
objSizeMap.emplace(characterType::humanplayer, objSize);

The auto keyword can also be useful to avoid having to write long type names
1
2
3
4
5
6
auto range = objSizeMap.equal_range(characterType::enemy);

for (auto it = range.first; it != range.second; ++it)
{
	// do something with *it.
}
Last edited on
Peter87,

Thank you so much for that quick reply and for all the extra information. I was able to put everything to use except the emplace function which seems to be for unordered multimaps. The insert with brackets did the job fine though, and the code looks so much more elegant with the auto and range feature!

There is just one final thing and I wont bug you on this. That is with passing the objSizeMap object over a function within a class in a separate file. I've searched the net and the only solution that came up is the solution that is used below, but compiles with error:

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
// game.h
#ifndef GAME_H
#define GAME_H
#include <vector>

enum struct characterType
{
	object,
	humanplayer,
	enemy,
	editing,
	null
};


class DrawScreen;

class Game
{
	
public:
	Game();
	~Game();
	
	// the function i'm trying to pass through to
	void testFunc(DrawScreen &Draw, );

private:
	
	// current playing character
	characterType character = characterType::humanplayer;	

};

#endif // Game_H  



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
// drawscreen.h
#ifndef DRAWSCREEN_H
#define DRAWSCREEN_H

struct objSizeType
{
	int ybottom;
	int xleft;
	int ytop;
	int xright;
};

class Game; 

class DrawScreen
{
	
public:
	DrawScreen();
	~DrawScreen();
	
	// made public for now whilst troubleshooting
	std::multimap<characterType, objSizeType> objSizeMap;
	

	// seems to work fine in this fuction and others within DrawScreen class
	void DrawScreen::objSize();

private:
	
};
#endif // drawscreen_H  




I've tried many other ways. So far this is the error that pops up:
1
2
3
4
game.h:164:63: error: ‘objSizeType’ was not declared in this scope
game.h:164:74: error: template argument 2 is invalid
game.h:164:74: error: template argument 4 is invalid
game.cpp:846:6: error: prototype forvoid Game::testFunc(DrawScreen&, std::multimap<characterType, objSizeType>)’ does not match any in class ‘Game’
Okay, figured it out:

auto range = Draw.objSizeMap.equal_range(characterType::humanplayer);

I just needed to add 'Draw.'

:)
Is there any way to store the iterator as an object? Or at least use it as a reference it?

1
2
3
4
5
6
7
8
9
10
11
12
auto range = objSizeMap.equal_range(characterType::enemy);

for (auto it = range.first; it != range.second; ++it)
{
	// do something with *it.
}

// this is what i would like to do:

objSizeType tempObj

tempObj = it.second;
The iterator is already an object but I guess that is not what you mean.

You can of course copy the objSizeType object into another object if you like.
objSizeType tempObj = it->second;

If you don't want a copy, but a reference, you can do that as well.
objSizeType& tempObj = it->second;
Peter87,

Once again, thank you. It's amazing how such a small thing like an arrow insertion operator can change everything. The compiler wasn't giving me much info on this error.

Anyways, I have alot of learning to do! :)
Topic archived. No new replies allowed.