如果我有一个值向量并想要检查它们是否完全相同,那么在C ++中有效地执行此操作的最佳方法是什么?如果我用R之类的其他语言进行编程,我的思维方式就是只返回容器的唯一元素,然后如果唯一元素的长度大于1,我知道元素不能相同。在C ++中,这可以这样做:
//build an int vector
std::sort(myvector.begin(), myvector.end());
std::vector<int>::iterator it;
//Use unique algorithm to get the unique values.
it = std::unique(myvector.begin(), myvector.end());
positions.resize(std::distance(myvector.begin(),it));
if (myvector.size() > 1) {
std::cout << "All elements are not the same!" << std::endl;
}
然而,关于互联网和SO的阅读,我看到其他答案,例如使用set或find_if算法。那么最有效的方法是什么?为什么?我想我的不是最好的方法,因为它涉及排序每个元素然后调整向量的大小 - 但也许我错了。
谢谢, 本。
答案 0 :(得分:47)
您无需使用std::sort
。它可以用更简单的方式完成:
if ( std::adjacent_find( myvector.begin(), myvector.end(), std::not_equal_to<>() ) == myvector.end() )
{
std::cout << "All elements are equal each other" << std::endl;
}
答案 1 :(得分:25)
您可以使用std::equal
版本1:
//assuming v has at least 1 element
if ( std::equal(v.begin() + 1, v.end(), v.begin()) )
{
//all equal
}
这会将每个元素与前一个元素进行比较。
版本2:
//assuming v has at least 1 element
int e = v[0]; //preferably "const auto& e" instead
bool all_equal = true;
for(std::size_t i = 1,s = v.size();i<s && all_equal;i++)
all_equal = e == v[i];
编辑:
关于性能,在使用100m元素进行测试后,我发现Visual Studio 2015 version 1
中的大约是version 2
的两倍。这是因为当您使用ints,float等时,vs2015的最新编译器在c ++ std实现中使用sse instructions。
如果您使用_mm_testc_si128,您将获得与std::equal
答案 2 :(得分:11)
在向量上没有约束的情况下,无论方法如何,都必须至少迭代一次向量。所以只需选择第一个元素并检查所有其他元素是否等于它。
答案 3 :(得分:2)
排序是O(NlogN)任务。
这很容易在O(N)中解决,所以你目前的方法很差。
一个简单的O(N)将如Luchian Grigore所建议的那样,迭代向量,只需一次,将每个元素与第一个元素进行比较。
答案 4 :(得分:2)
虽然std::unique
的渐近复杂度是线性的,但操作的实际成本可能比您需要的要大得多,而且它是一个就地算法(它会随着时间的推移修改数据)。
最快的方法是假设如果向量包含单个元素,则根据定义它是唯一的。如果向量包含更多元素,那么您只需要检查它们是否都与第一个完全相同。为此,您只需要找到与第一个元素不同的第一个元素,从第二个元素开始搜索。如果存在这样的元素,则元素不是唯一的。
if (v.size() < 2) return true;
auto different = std::find_if(v.begin()+1, v.end(),
[&v](auto const &x) { x != v[0]; });
return different == v.end();
这是使用C ++ 14语法,在C ++ 11工具链中,您可以在lambda中使用正确的类型。在C ++ 03中,您可以使用std::not
,std::bind1st/std::bind2nd
和std::equal
的组合代替lambda。
这种方法的成本是distance(start,different element)
比较,没有副本。比较次数中的预期和最差情况线性成本(并且没有副本!)
答案 5 :(得分:2)
if(std::all_of(myvector.begin()+1, myvector.end(), std::bind(std::equal_to<int>(),
std::placeholders::_1, myvector.front())) {
// all members are equal
}
答案 6 :(得分:1)
在您的特定情况下,迭代向量元素并从第一个元素中查找不同的元素就足够了。在评估向量中的所有元素之前,您甚至可能会幸运地停下来。 (可以使用while循环,但出于可读性原因,我坚持使用for循环)
bool uniqueElt = true;
int firstItem = *myvector.begin();
for (std::vector<int>::const_iterator it = myvector.begin()+1; it != myvector.end() ; ++it) {
if(*it != firstItem) {
uniqueElt = false;
break;
}
}
如果您想知道矢量包含多少个不同的值,您可以构建一个集合并检查其大小以查看其中有多少个不同的值:
std::set mySet;
std::copy(mySet.begin(), myvector.begin(), myvector.end());
答案 7 :(得分:1)
您可以使用FunctionalPlus(https://github.com/Dobiasd/FunctionalPlus):
std::vector<std::string> things = {"same old", "same old"};
if (fplus::all_the_same(things))
std::cout << "All things being equal." << std::endl;
答案 8 :(得分:1)
也许是这样的。它只遍历矢量一次,并且不会混淆矢量内容。
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::count_if(values.begin(), values.end(), [ &values ] (auto size) { return size == values[0]; }) == values.size();
如果向量中的值与基本类型不同,则必须实现相等运算符。
考虑到underscore_d备注后,我正在改变可能的解决方案
std::vector<int> values { 5, 5, 5, 4 };
bool equal = std::all_of(values.begin(),values.end(),[ &values ] (auto item) { return item == values[0]; });
答案 9 :(得分:1)
您只需使用std::count
来计算与起始元素匹配的所有元素:
std::vector<int> numbers = { 5, 5, 5, 5, 5, 5, 5 };
if (std::count(std::begin(numbers), std::end(numbers), numbers.front()) == numbers.size())
{
std::cout << "Elements are all the same" << std::endl;
}
答案 10 :(得分:1)
使用std :: all_of和C ++ 11 lambda
if (all_of(values.begin(), values.end(), [&] (int i) {return i == values[0];}){
//all are the same
}
答案 11 :(得分:0)
为了完整起见,因为它仍然不是最有效的,你可以用更有效的方式使用std :: unique来决定所有成员是否相同,但要注意使用std :: unique后容器无用的方式:
#include <algorithm>
#include <iterator>
if (std::distance(cntnr.begin(), std::unique(cntnr.begin(), cntnr.end()) == 1)
{
// all members were the same, but
}
答案 12 :(得分:0)
使用C++ 14
的另一种方法:
bool allEqual = accumulate(v.begin(), v.end(), true, [first = v[0]](bool acc, int b) {
return acc && (b == first);
});
它也是N阶。
答案 13 :(得分:0)
LLVM提供了一些独立可用的标头和库:
#include <llvm/ADT/STLExtras.h>
if (llvm::is_splat(myvector))
std::cout << "All elements are the same!" << std::endl;