std::向量中的重复元素
Repeated elements in a std::vector
我有一个std::vector
,我想检查其中的所有元素。如果某个元素出现多次,我会发出错误信号。
我就是这样做的:
std::vector<std::string> test;
test.push_back("YES");
test.push_back("YES");
for(int i = 0; i < test.size(); i++)
{
if(test[i] > 1)
{
DCS_LOG_DEBUG("ERROR WITH COUNT")
}
}
虽然我知道如何使用std::vector::count()
方法进行计数,但这并不奏效。但我想得到每个元素的计数,而不是计算所有元素。。。有什么想法吗?
最简单的方法是std::sort
矢量,然后使用std::adjacent_find
。
然而,如果你不想对向量进行排序,你可以在C++11:中这样做
#include <unordered_map>
#include <functional> // For std::hash<std::string>.
#include <string>
#include <iostream>
int main() {
// Test data.
std::vector<std::string> v;
v.push_back("a");
v.push_back("b");
v.push_back("c");
v.push_back("a");
v.push_back("c");
v.push_back("d");
v.push_back("a");
// Hash function for the hashtable.
auto h = [](const std::string* s) {
return std::hash<std::string>()(*s);
};
// Equality comparer for the hashtable.
auto eq = [](const std::string* s1, const std::string* s2) {
return s1->compare(*s2) == 0;
};
// The hashtable:
// Key: Pointer to element of 'v'.
// Value: Occurrence count.
std::unordered_map<const std::string*, size_t, decltype(h), decltype(eq)> m(v.size(), h, eq);
// Count occurances.
for (auto v_i = v.cbegin(); v_i != v.cend(); ++v_i)
++m[&(*v_i)];
// Print strings that occur more than once:
for (auto m_i = m.begin(); m_i != m.end(); ++m_i)
if (m_i->second > 1)
std::cout << *m_i->first << ": " << m_i->second << std::endl;
return 0;
}
此打印:
a: 3
c: 2
我实际上并没有对它进行基准测试,但这有机会表现得相当出色,原因如下:
- 假设实际的向量元素不会产生病态的不平衡散列,这实际上是一种O(n)算法,而不是用于排序的O(n*log(n))
- 我们使用指针到字符串的哈希表,而不是字符串本身,因此不会发生不必要的复制
- 我们可以"预分配"哈希表桶(在构造
m
时传递v.size()
),因此哈希表大小被最小化
特定元素
计数是标准的方法:
#include <algorithm>
...
if (count (test.begin(), test.end(), "YES") > 1)
std::cerr << "positiven";
如果你需要更多的性能,你可以用经典的方法:
bool exists = false;
for (auto const& v : test) {
if (v == "YES") {
if (exists) {
std::cerr << "positiven";
break;
}
else exists = true;
}
}
任意元素多次
对于大矢量,请尝试std::set
:
std::set<std::string> exists;
for (auto const &v : test) {
if (!exists.insert(v).second)
std::cerr << "positiven";
}
在这种方法中,如果你也想识别你是否已经提到了它的非唯一性,你可能想使用std::multiset
:
const std::multiset<std::string> counts (test.begin(), test.end());
for (auto const &v: test)
if (counts.count (v) == 2) std::cerr << "mehn";
如果容器很小,并且您只想查看是否有任何元素不止一次存在:
auto multitimes = [&test] (std::string const &str) {
return count(test.begin(),test.end(),str)>1;
};
if (any_of (test.begin(), test.begin(), multitimes))
std::cerr << "something was there more than oncen";
您可以使用std::map定义从键(字符串)到计数(int)的映射:
#include <map>
#include <string>
/* ... */
std::map<std::string, int> count_map;
/* ... */
count_map[key]++;
使用std::count对元素进行计数:http://www.cplusplus.com/reference/algorithm/count/
http://en.cppreference.com/w/cpp/algorithm/count
sort(test.begin(), test.end());
// If you only care if there is a repeated element, do this:
int size = test.size();
unique(test.begin(), test.end());
if (test.size() != size) {
cout << "An element is repeated.";
}
// If you do care which elements are repeated, do this:
for (unsigned index = 1; index < test.size(); ++index) {
if (test[index] == test[index - 1] && (index == 1 || test[index - 2] != test[index])) {
cout << test[index] << " is repeated.";
}
}
我提供了两种解决方案:第一种是只关心字符串是否重复,第二种是关心哪些字符串重复。
如果您不介意额外的空间,请尝试将元素推入map
。只要您发现元素已经在地图中,就可以直接发出错误信号。
map<string, int> occurrences;
for (vector<string>::const_iterator cit = test.begin(); cit != test.end(); ++cit)
if ((++occurrences[*cit]) == 2)
cout << "ERROR"; // You can even signal which element is repeated here easily, using *cit.
请注意,根据Tony Delroy的巧妙修正,该代码对每个重复的项目只正确地发出一次消息(即使该项目重复了很多次)。尽管这种方式正确地统计了整个集合中每个字符串的出现次数(这可能是必需的),但如果同一元素(或多个)有2个31副本,这种方式会导致int
溢出。如果是这种情况,并且您确实需要每个字符串的计数,则可以使用long long int
。
如果你对每个字符串的计数不感兴趣,一种更有效的方法是使用set
,正如smerlin所建议的那样(因为它只维护字符串,而不是像map
那样维护一对字符串和int
),从而减少空间需求。。。并且每当您在集合中找到项目时都会发出错误消息:
set<string> occurrences;
for (vector<string>::const_iterator cit = test.begin(); cit != test.end(); ++cit)
if (false == occurrences.insert(*cit).second)
cout << "ERROR"; // You can even signal which element is repeated here easily, using *cit.
如果您想在问题发生之前消除它,请将元素插入到set
中。它会自动删除重复项。但是要注意set
中的元素是经过排序的,因此不会保留插入顺序。如果你不介意的话,set
要好得多,因为搜索它和按排序顺序读取元素要高效得多。
一个解决方案可以使用两个for循环。。。。我想这会很简单。。
例如:
std::vector<std::string> test;
test.push_back("YES");
test.push_back("YES");
for(int i = 0; i < test.size(); i++)
{
for(int j = 0; j < test.size(); j++)
{
if(i != j)
{
if(test[i] == test[j])
{
DCS_LOG_DEBUG("ERROR WITH COUNT")
}
}
}
}
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- C++:如何循环通过向量中的整数元素
- 如何在C++向量中奇数元素前面加上值-1,我在使用insert函数时遇到了问题
- 不允许在向量中添加更多元素
- 基于范围的 for 循环:迭代使用一个元素扩展的向量
- 使用并行参数向量调用元素向量的成员函数
- C++ 查找字符串中存在的元素向量
- 包含 std::threads 的元素向量
- 避免从单一元素向量转换为基元类型
- 对自定义元素向量进行排序时出现意外(至少对我来说)行为
- 如何为对元素(向量和int)配对创建unique_ptr也是unique_ptr
- 元素向量乘法 C++(代码不起作用)
- 时间和空间复杂性在二叉树的每个级别创建元素向量(NON-BST)
- 遍历结构元素向量
- 犰狳C++中的元素向量或矩阵乘法
- 为什么'std::vector<int> b{2};'创建 1 元素向量,而不是 2 元素向量?
- 可移动元素向量的大小调整是否有效?
- 唯一元素向量的c++模板函数
- 获取索引和元素-向量问题
- 定义一个生成元素向量的函数时,正确的方法是什么?