I know it is a very bad idea, so other suggestions on how to do it efficiently will be well-received.
Here's the thing. I have map<string,vector<string> >
, I want to search for a key and return its corresponding value (vector of strings in this case). Reason I insist on returning (rather than just iterating) is I need to search the values returned in some other vector.
An example will make this clear:
Input:
key1 ---> {2,3,4}
key2 ---> {1}
key3 ---> {2,12,11,9}
For key1 as input, vector with values 2,3,4 should be returned. Now these 2,3,4 values need to be searched in other vector of strings. What is the most efficient way to do this?
I tried something like this:
vector<string> returnEdges(string key)
{
for (map<string, vector<string> >::iterator it=outgoing.begin();
it!=outgoing.end();++it)
{
if (key.compare((*it).first)==0)
{
return (*it).second;
}
}
//return string<;//what should I return here????
}
1) How should I return empty vector in case key is not found?
2) what is the best way to implement this?
I hope the question is clear.
EDIT: As I wrote the question, I thought why not return an iterator? Do the people at SO give their approval for this idea?
Return vector function : vector<string> Mimic::getSuffixList(string prefix){ int find=0; for(int i =0; i < map. size(); i++) { if(map[i]. prefix == prefix) { find =1; return map[i].
Explanation to the Code:Declare using std::cout and std::vector. Declare function with vector type return type which accepts vector as a variable. Then return null vector inside function body.
The push_back() member function is provided to append characters. Appends character c to the end of the string, increasing its length by one. Syntax : void string:: push_back (char c) Parameters: Character which to be appended.
vector::empty() The empty() function is used to check if the vector container is empty or not.
1) Returning an iterator is a fine idea. When you do this, the natural way to indicate the "not found" case is to return the .end() iterator. This has the down-side that the abstraction is somewhat leaky: the caller has to be able to get at this .end() value in order to compare to it for error checking, and the returned iterator exposes a richer interface than you'd like (the client code shouldn't really play around with incrementing and decrementing the iterator).
2) Returning an empty vector is as simple as creating an empty vector and returning it. Creating an empty vector = constructing a vector which is empty. This is what you get from - drum roll - the default constructor of the vector class.
3) You don't need to, and shouldn't, implement the search loop yourself. The standard library already implements this for you. (There is a specialized find
function for map
s because of the key/value distinction. For sequences like list
, vector
and deque
, prefer the free function std::find
, which comes from <algorithm>
.
4) You should prefer to accept function parameters (when they are instances of classes, like std::string
) and return data (especially complex things like a vector of strings) by const reference. Passing and returning by value implies a copy; sometimes the compiler can optimize this away, but it's not as reliable as we'd like. Besides, the reason you're using C++ in the first place is to have that level of control over things, right? If not, then don't torture yourself with it.
However, you can't do that if you're going to return a newly-created value some of the time. Yet another way to design the interface is to return a pointer to the vector of strings (note that pointer arithmetic on these will be invalid) within the map, or a NULL pointer if the value is not found. This avoids copying and distinguishes a "not found" result from an actual empty vector within the data, but it means the client code has to deal with an icky raw pointer.
5) Having 'return' in the name of a function is useless, as returning is what functions do. OTOH, it is a good idea to name things in a way that makes it evident why the parameters are what they are.
6) With iterators for complex types, it is often a good idea to set up typedefs.
Returning an iterator is as simple as:
typedef map<string, vector<string> >::iterator graph_iterator;
graph_iterator edges_named(const string& node_name) {
return outgoing.find(node_name);
}
Returning a vector of strings is as simple as:
typedef map<string, vector<string> >::iterator graph_iterator;
vector<string> edges_named(const string& node_name) {
graph_iterator it = outgoing.find(node_name);
return it == outgoing.end() ? vector<string>() : it->second;
}
Returning a pointer is as simple as:
typedef map<string, vector<string> >::iterator graph_iterator;
vector<string>* edges_named(const string& node_name) {
graph_iterator it = outgoing.find(node_name);
return it == outgoing.end() ? NULL : &(it->second);
}
Choose wisely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With