检查向量的所有元素在C++中是否相等
Checking if all elements of a vector are equal in C++
如果我有一个值向量并想检查它们是否都相同,那么有效地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
算法。那么最有效的方法是什么,为什么呢?我想我的不是最好的方法,因为它涉及对每个元素进行排序,然后调整向量的大小 - 但也许我错了。
你不需要使用 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;
}
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
的两倍。这是因为 vs2015 的最新编译器在使用 ints、float 等时,在 c++ std 实现中使用 sse 指令。
如果您使用_mm_testc_si128您将获得与std::equal
类似的性能
使用 std::all_of 和 C++11 lambda
if (all_of(values.begin(), values.end(), [&] (int i) {return i == values[0];})){
//all are the same
}
如果对向量没有约束,则无论采用何种方法,都必须至少遍历一次向量。因此,只需选择第一个元素并检查所有其他元素是否都等于它。
虽然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)
比较,没有副本。比较次数中的预期和最坏情况线性成本(没有副本!
排序是一项O(NlogN(任务。
这很容易在O(N(中求解,所以你目前的方法很差。
一个简单的O(N(就像Luchian Grigor建议的那样,迭代向量一次,将每个元素与第一个元素进行比较。
if(std::all_of(myvector.begin()+1, myvector.end(), std::bind(std::equal_to<int>(),
std::placeholders::_1, myvector.front())) {
// all members are equal
}
您可以使用 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;
也许是这样的。它只遍历矢量一次,不会弄乱矢量内容。
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]; });
在您的特定情况下,迭代向量元素并找到与第一个元素不同的元素就足够了。您甚至可能很幸运地在评估向量中的所有元素之前停下来。(可以使用 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());
您可以简单地使用 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;
}
LLVM 提供了一些独立可用的标头 + 库:
#include <llvm/ADT/STLExtras.h>
if (llvm::is_splat(myvector))
std::cout << "All elements are the same!" << std::endl;
https://godbolt.org/z/fQX-jc
完整起见,因为它仍然不是最有效的,你可以以更有效的方式使用 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
}
使用C++ 14
的方法:
bool allEqual = accumulate(v.begin(), v.end(), true, [first = v[0]](bool acc, int b) {
return acc && (b == first);
});
这也是 N 阶。
这是一个可读的 C++17 解决方案,可能会提醒学生std::vector
的其他构造函数:
if (v==std::vector(v.size(),v[0])) {
// you guys are all the same
}
。在 C++17 之前,std::vector
右值需要显式提供其类型:
if (v==std::vector<typename decltype(v)::value_type>(v.size(),v[0])) {
// you guys are all the same
}
C++函数在 STL 的库中定义。此函数对整个数组元素进行操作,可以节省运行循环以逐个检查每个元素的时间。它检查每个元素上的给定属性,并在范围中的每个元素满足指定属性时返回 true,否则返回 false。
// C++ code to demonstrate working of all_of()
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> v(10, 2);
// illustrate all_of
if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; }))
{
std::cout << "All numbers are evenn";
}
}
- 在提升multi_index容器中,是否定义了"default index"?
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 检查输入是否不是整数或数字
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 此代码是否违反一个定义规则
- 是否需要删除包含对象的"pair"?
- 是否可以从int转换为enum类类型
- 无论条件是否为true,if总是在c++中执行
- 如何找到大小'x'数组是否完全填充,在C++?
- 检查值是否在集合p1和p2中,但不在p3中
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- C/C++预处理器是否可以检测一些编译器选项
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话