C++ equivalent of Python difference_update?
C++ equivalent of Python difference_update?
s1 和 s2 是集合(Python set 或 C++ std::set)
要将 s2 的元素添加到 s1(集合联合),您可以执行
Python: s1.update(s2)
C++: s1.insert(s2.begin(), s2.end());
要从 s2 中删除 s1 的元素(设置差分),您可以执行
Python: s1.difference_update(s2)
这C++等价物是什么?代码
s1.erase(s2.begin(), s2.end());
不起作用,因为 s1.erase() 需要来自 s1 的迭代器。代码
std::set<T> s3;
std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s3, s3.end());
s1.swap(s3);
工作,但似乎过于复杂,至少与 Python 相比。
有没有更简单的方法?
使用 std::set_difference
是C++中执行此操作的惯用方法。 您偶然发现了C++/STL与许多其他语言之间的主要差异之一(双关语)。 STL 不直接将操作与数据结构捆绑在一起。 这就是std::set
不实现差异例程的原因。
基本上,诸如std::set_difference
之类的算法将操作的结果写入另一个对象。 有趣的是,该算法并不要求一个或两个操作数实际上是std::set
。 该算法的定义是:
效果:将范围
[first1, last1)
中不存在的范围元素复制到从result
开始的范围[first2, last2)
。 对构造区域中的元素进行排序。要求:生成的范围不得与任一原始范围重叠。 输入范围需要按同一
operator<
排序。返回:构造范围的结束。
复杂性:最多
2 * ((last1 - first1) + (last2 - first2)) - 1
比较
有趣的区别在于C++版本适用于任何两个排序范围。 在大多数语言中,您被迫强制或将调用对象(左操作数)转换为集合,然后才能访问集合差分算法。
这与你的问题并不真正相关,但这就是各种集合算法被建模为独立算法而不是成员方法的原因。
你应该遍历第二个集合:
for( set< T >::iterator iter = s2.begin(); iter != s2.end(); ++iter )
{
s1.erase( *iter );
}
这可能比使用 std::set_difference
便宜 - set_difference
将唯一对象复制到新容器中,但这需要线性时间,而.erase
不会复制任何内容,而是O(n * log( n ) )
。
换句话说,取决于容器,您可以选择方式,这对您的情况来说会更快。
谢谢David Rodríguez - dribeas
的评论!(:
编辑:嘟!我一开始就想过BOOST_FOREACH,但我错了,它不能使用。- 你不需要迭代器,只需要值。正如用户763305自己所说。
在 c++ 中,集合中没有difference
方法。set_difference
看起来更笨拙,因为它比在两组上应用差异更通用。当然,你可以在集合上实现你自己的就地差分版本:
template <typename T, typename Compare, typename Allocator>
void my_set_difference( std::set<T,Compare,Allocator>& lhs, std::set<T,Compare,Allocator> const & rhs )
{
typedef std::set<T,Comapre,Allocator> set_t;
typedef typename set_t::iterator iterator;
typedef typename set_t::const_iterator const_iterator;
const_iterator rit = rhs.begin(), rend = rhs.end();
iterator it = lhs.begin(), end = lhs.end();
while ( it != end && rit != rend )
{
if ( lhs.key_comp( *it, *rit ) ) {
++it;
} else if ( lhs.key_comp( *rit, *it ) ) {
++rit;
} else {
++rit;
lhs.erase( it++ );
}
}
}
此算法的性能在参数大小上将是线性的,并且不需要额外的副本,因为它会就地修改第一个参数。
你也可以通过编写自己的函子来remove_if
测试集合中的存在性,例如
std::remove_if(s1.begin(), s1.end(), ExistIn(s2));
我想set_difference
更有效,因为它可能只扫描两组一次
unordered_set,而不是 std::set,它是有序的。
David Rodríguez 的算法依赖于 std::set 是有序的,因此 lhs 和 rhs 集合可以按照算法中所示的方式遍历。
对于适用于有序和无序集合的更通用的解决方案,如果您正在强制执行/保留 Python 集合的"无序"性质,Kiril Kirov 的算法应该是安全的算法。
- Difference in displaying cv2 Mat
- Visual Studio Professional 2013, Update 5, "No Target Architecture"
- 对目录进行更改后,如何"update" diretory_iterator?
- Difference atexit() and at_quick_exit()
- Windows Creators Update 會厮敗舊的C++應用程序
- QT4:在所有qgraphicsItem上的单个qgraphictem rapers paint()上的update()
- Windows 10 Creators Update(1703)崩溃了我们的应用程序
- C++ Qt GUI update
- 当Bool值在UPDATE()方法中更改时,只有一次呼叫函数
- vtk c++ update contour from contourfilter
- Difference Between c.foo() and c.parent::foo()
- FFMPEG:av_rescale_q - time_base difference
- QObject::使用update()函数连接计时器
- 使用CNTK 2.1.0 GPU的学习率设置,vs 2015 Update 3,C ,窗口
- vs 2012 Ultimate Update 4不会编译数组
- SQLLITE UPDATE语句不起作用
- 在std::字符串或字符数组中间包含NULL字符的UPDATE
- 找不到QT 5.6 update()函数标识符
- Visual C++, Windows Update Interface (IUpdate) <wuapi.h>, get_MsrcSeverity
- 有人知道为什么使用本机c++的Visual Studio 2015 Update 2中的intellisense速度太慢