查找 3 个 C++ 中的 1 个集合唯一的单词

Posted

技术标签:

【中文标题】查找 3 个 C++ 中的 1 个集合唯一的单词【英文标题】:Find words that are unique for 1 set out of 3 C++ 【发布时间】:2020-03-13 13:23:46 【问题描述】:

我有 3 个包含单词的集合。

a: car, boat, table, ball

b: car, goat, helicopter

c: square, car, goat, boat

我需要创建一个向量或集合,其中包含仅包含在集合 a 中的单词。

所以答案是:

result: table, ball

我尝试使用 set_difference 和 set_intersection 来实现它,但到目前为止没有运气。你能给我一些建议吗?

我试过了

set_difference(a.begin(), a.end(), b.begin(), b.end(), res.begin()); 
set_difference(res.begin(), res.end(), c.begin(), c.end(), res.begin());

但是结果是空的

【问题讨论】:

std::set_difference 是此作业的标准工具。您可以使用它显示您的代码,我们可以帮助您修复它吗? 您在使用std::set_difference之前是否对数组进行了排序? 实际上我无法理解如何将 3 套而不是 2 套放入std::set_difference 你没有。您对ab 运行差异创建输出d。然后你对 dc 运行差异创建你的结果集。 第二行写错了。您在迭代 res 时正在修改它。您应该使用final_res 变量来存储第二个结果。 【参考方案1】:

你的错误在这里:

set_difference(res.begin(), res.end(), c.begin(), c.end(), res.begin());
//             ^            ^                              ^

您遍历res 并将结果写入同一个集合中。您需要另一组来存储结果。

解决方案是:

std::set<std::string> a "car", "boat", "table", "ball";
std::set<std::string> b "car", "goat", "helicopter";
std::set<std::string> c "square", "car", "goat", "boat";

std::set<std::string> tmp;
std::set<std::string> res;

// Difference between a and b --> stored in tmp
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(tmp, tmp.begin()));

// Difference between tmp and c --> stored in res
std::set_difference(tmp.begin(), tmp.end(), c.begin(), c.end(), std::inserter(res, res.begin()));

for(const std::string & s : res)
    std::cout << s << '\n';

输出:

球 表

Live example


注意:如果我们查看std::set_difference的文档,我们可以看到:

将排序范围 [first1, last1) 中未在排序范围 [first2, last2) 中找到的元素复制到从 d_first 开始的范围内。

结果范围也被排序。 等价元素被单独处理,即如果某个元素在[first1,last1)中找到m次,在[first2,last2)中找到n次,则将其准确复制到d_first std::max(m-n, 0 ) 次。结果范围不能与任何一个输入范围重叠。

强调我的

所以如果你想使用另一个不保证其元素唯一性的容器(例如std::vector),你需要自己确保每个元素不会在你的容器中出现多次。


注意2:如果你不想打扰tmp set(拿到res set后就没用了),你可以把它放在一个bloc中,这样它之后会被销毁:

std::set<std::string> res;


    std::set<std::string> tmp;
    std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(tmp, tmp.begin()));
    std::set_difference(tmp.begin(), tmp.end(), c.begin(), c.end(), std::inserter(res, res.begin()));
 // tmp destroyed here

Live example

【讨论】:

【参考方案2】:

如果不共享您的代码,我们只能猜测您的代码做错了什么。

这就是我所做的。我将差异逻辑包装在一个助手 operator- 中。我故意使用std::unordered_set,因为它们不能直接在std::set_difference中使用。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_set>
#include <vector>

using std::cout;
using std::inserter;
using std::ostream;
using std::set_difference;
using std::sort;
using std::string;
using std::unordered_set;
using std::vector;

namespace 

unordered_set<string> operator-(unordered_set<string> const& minuend, unordered_set<string> const& subtrahend) 
    vector<string> m(minuend.begin(), minuend.end());
    vector<string> s(subtrahend.begin(), subtrahend.end());
    sort(m.begin(), m.end());
    sort(s.begin(), s.end());
    unordered_set<string> diff;
    set_difference(m.begin(), m.end(), s.begin(), s.end(), inserter(diff, diff.begin()));
    return diff;


ostream& operator<<(ostream& out, unordered_set<string> const& container) 
    char const* sep = " ";
    out << "";

    for (auto const& s : container) 
        out << sep << "\"" << s << "\"";
        sep = ", ";
    
    out << " ";
    return out;




int main() 
    auto a = unordered_set<string> "car", "boat", "table", "ball" ;
    auto b = unordered_set<string> "car", "goat", "helicopter" ;
    auto c = unordered_set<string> "square", "car", "goat", "boat" ;
    auto d = a - b - c;
    cout << d << "\n";

更新回答 Fareanor 的问题

你为什么使用 std::unordered_set(而不是 std::set)?

我选择了 unordered_set 来证明 set_difference 需要一个有序的容器。 unordered_set 缺少该功能。

原始海报,在原始未经编辑的问题中,没有提供使用哪种容器的详细信息。

为什么要将它转换成需要排序的 std::vector(而不是转换成 std​​::set)?

向量是一个非常有效的容器,因为其中的元素具有局部性,因此具有良好的缓存。这是我的首选容器。

一个集合有更多的内存分配,因为它是一个节点网格,并且缺乏局部性。

无论如何,包含的字符串对象可能缺少局部性,因为它基本上是一个指向字符数组的智能指针。但由于小字符串优化 (SSO) 和这些都是小字符串,它也不会在堆外分配。

在原发帖人的场景中,每个容器中只有几件物品,因此效率问题可以忽略不计。但值得考虑的是,如果问题域扩大了。

我认为你应该使用 std::set (至少没有来自 OP 的任何澄清),如果用户得到一个 std::unordered_set ,则由他将其转换为适当的 std ::set 然后打电话给你的operator-()

这是一个可行的选择。由于当时缺乏上下文,我认为这是“更糟糕的情况”,因为 unordered_set 容器不满足 set_difference 算法的要求。

【讨论】:

我喜欢你的想法,它非常优雅。但是有几件事我不明白:你为什么使用std::unordered_set(而不是std::set)?为什么将其转换为需要排序的std::vector(而不是转换为std::set)?我认为您应该使用std::set(至少没有任何来自OP的澄清),如果用户得到std::unordered_set,则由他将其转换为正确的std::set,然后致电您的@987654333 @.

以上是关于查找 3 个 C++ 中的 1 个集合唯一的单词的主要内容,如果未能解决你的问题,请参考以下文章

将浮点数组写入和附加到 C++ 中 hdf5 文件中的唯一数据集

C++ 结构集无法按元素查找/擦除

如何创建集合扩展以在具有属性的集合中查找唯一对象?

给定元素集的唯一(有限长度)组合 - Matlab 中的实现

查找两个大型数据集之间的最近坐标

检查两个字符串是不是在 Python 中包含相同的单词集