2011-09-16 20 views
5

我知道这是一个非常糟糕的主意,所以有关如何有效执行此操作的其他建议将很受欢迎。如果找不到密钥,则返回一个空的字符串向量

这是事情。我有map<string,vector<string> >,我想要搜索一个键并返回其相应的值(在这种情况下是字符串的向量)。我坚持返回(而不是仅仅迭代)的原因是我需要搜索其他向量中返回的值。

一个例子明确这一点:

Input: 

key1 ---> {2,3,4} 
key2 ---> {1} 
key3 ---> {2,12,11,9} 

对于KEY1作为输入,其值2,3,4载体应被返回。现在这些2,3,4值需要在其他字符串向量中搜索。什么是最有效的方法来做到这一点?

我想是这样的:

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)我应该如何返回键的情况下空载体是不是发现了什么?

2)实现此目的的最佳方法是什么?

我希望问题很清楚。

编辑:当我写这个问题,我想为什么不返回一个迭代器? SO的人们是否赞同这个想法?

回答

4

1)返回一个迭代器是一个好主意。当你这样做时,指明“未找到”情况的自然方法是返回.end()迭代器。这有一个缺点,抽象是有点漏洞:调用者必须能够得到这个.end()值,以便与错误检查进行比较,并且返回的迭代器暴露的界面比您想要的更丰富像(客户端代码不应该真正玩弄递增和递减迭代器)。

2)返回空向量与创建空向量并返回它一样简单。创建一个空矢量=构造一个空的矢量。这是你得到的 - 鼓轮 - 矢量类的默认构造函数。

3)你不需要,也不应该自己实现搜索循环。标准库已经为你实现了。 (这里是因为键/值区分map个专门find功能。对于像listvectordeque序列,更喜欢自由的功能std::find,这来自<algorithm>

4)你应该更喜欢接受功能参数(当它们是类的实例时,如std::string)并通过const引用返回数据(特别是像字符串向量这样的复杂事物)。按价值传递和返回意味着副本;有时编译器可以优化它,但它不如我们想要的那么可靠。此外,你首先使用C++的原因是对事物的控制水平,对吧?如果不是,那就不要用它折磨自己。

但是,如果您要在某些时间返回新创建的值,则无法这样做。设计接口的另一种方式是在映射内返回一个指针到字符串向量(注意这些字符串的指针算法将无效),或者如果找不到该值,则返回NULL指针。这样可以避免复制和区分数据中实际空向量的“未找到”结果,但这意味着客户端代码必须处理一个恶意的原始指针。

5)以函数的名义返回''是无用的,因为返回是函数的作用。 OTOH,以某种方式来命名事物是一个好主意,这就是为什么参数是他们的原因。

6)对于复杂类型的迭代器,设置typedefs通常是一个好主意。

返回一个迭代很简单,只要:

typedef map<string, vector<string> >::iterator graph_iterator; 
graph_iterator edges_named(const string& node_name) { 
    return outgoing.find(node_name); 
} 

返回字符串矢量很简单,只要:

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; 
} 

返回指针是简单:

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); 
} 

明智地选择。

+0

我对这些原始指针感到有些不安。也许这种设计可能有用,但不知何故应该有更好的方法。 OP邀请解释她的目标;也许我们可以提出具体的建议。 –

+0

@Karl,真棒真棒回答。我认为这些问题很多人都喜欢我,他们从其他语言到C++,并且无法高效/有效地使用它 – Anon

+0

将迭代器转换为原始指针是限制接口的一种方法。然而,它仍然不会阻止递增/递减 - 它只是意味着它会中断(未定义的行为是**期望**在正常情况下崩溃,但是真正知道的是谁),而不是让用户将封装破坏为itty小块。可能更好的主意是创建一个包装类 - 一种故意愚蠢的智能指针。 :) –

2

如何:

std::vector<std::string> find_by_key_maybe(const std::string & key) 
{ 
    std::map<std::string, std::vector<std::string>>::const_iterator it = themap.find(key); 
    return it == themap.end() ? std::vector<std::string>() : it->second; 
} 

甚至,如果themap是非常量,你也想一空载体添加到地图:

std::vector<std::string> find_by_key_and_insert_if_missing(const std::string & key) 
{ 
    return themap[key]; 
} 

这是完全确定返回如果这是情况所要求的,那就是价值向量。

+0

注意,使用'themap [关键]'也将增加一个空载体到项下的地图。根据您的确切应用,这可以从令人难以置信的有用到完全不可接受,以及其间的任何地方。 –

+0

@Karl:哈,是的 - 我应该补充一点。谢谢! –

+0

谢谢。那么返回迭代器呢?效率不高吗? (虽然我可能在这里错了) – Anon

1

大多数情况下,你不需要返回向量的副本,const引用也可以。如果需要,您可以随后复制一份。

此外,您不需要遍历地图,它们已针对使用find方法进行搜索进行了优化。

const vector<string> & returnEdges(string key) 
{ 
    map<string, vector<string> >::iterator it = outgoing.find(key); 
    if (it == outgoing.end()) 
    { 
     static vector<string> empty_vector; 
     return empty_vector; 
    } 
    return it->second; 
} 
0

我认为operator []可以帮助你,它会返回一个空值(这里是一个空向量)。 因此,所有你需要做的是

vector<string> returnEdges(string key) 
{ 
    return outgoing[key]; 
} 
+0

正如我们上面已经讨论过的那样,这也*在地图中插入一个空值,这可能是也可能不是所希望的。 –

相关问题