【问题标题】:Finding duplicate tuples in a map of tuple in C++在 C++ 中的元组映射中查找重复的元组
【发布时间】:2020-09-22 06:24:36
【问题描述】:

我正在编写一种在集合中查找重复面孔的方法。该集合的类型是std::vector<std::tuple<int, int, int>> 所以,为了找到重复项,我尝试创建一个地图

`std::map<std::tuple<int, int, int>, int>` where key is tuple and value is the number of occurrences.

如果我添加以下数据,

  std::map<std::tuple<int, int, int>, int> faceMap;
    faceMap[std::make_tuple(0, 1, 2)]++;
    faceMap[std::make_tuple(0, 2, 1)]++;
    faceMap[std::make_tuple(1, 0, 2)]++;
    faceMap[std::make_tuple(1, 2, 0)]++;
    faceMap[std::make_tuple(2, 1, 0)]++;
    faceMap[std::make_tuple(2, 0, 1)]++;

我希望得到 faceMap,其中只有一个键值对,键为 [0,1,2],值为 6。

为了对此进行排序,我还尝试编写如下比较器

bool containsIndex(int toCheck, int i0, int i1, int i2)
{
    if (toCheck == i0 || toCheck == i1 || toCheck == i2)
        return true;
    else
        return false;
}

struct FaceTupleComparator {
    bool operator() (const std::tuple<int, int, int>& lhs,
        const std::tuple<int, int, int>& rhs) const
    {

        auto lv0 = std::get<0>(lhs);
        auto lv1 = std::get<1>(lhs);
        auto lv2 = std::get<2>(lhs);

        auto rv0 = std::get<0>(rhs);
        auto rv1 = std::get<1>(rhs);
        auto rv2 = std::get<2>(rhs);

        bool i0Found = false, i1Found = false, i2Found = false;
        if (containsIndex(lv0, rv0, rv1, rv2))
            i0Found = true;
        if (containsIndex(lv1, rv0, rv1, rv2))
            i1Found = true;
        if (containsIndex(lv2, rv0, rv1, rv2))
            i2Found = true;


        return !(i0Found && i1Found && i2Found);
    }
};

并将地图制作为std::map&lt;std::tuple&lt;int, int, int&gt;, int, FaceTupleComparator&gt; faceMap;

它不适用于所有将异常作为无效比较器抛出的情况。

如果有办法在这种类型的集合中找到重复项,有人可以帮我吗?

【问题讨论】:

  • 地图需要严格的弱排序,而不是相等运算符。像 operator&lt; 一样实现 operator()
  • 请查看std::map 的比较器要求。您不能只是忽略要求并将其他一些功能融入其中。如果您尝试这样做,则会在内部破坏数据结构。
  • 无需编写复杂的比较器,您只需对元组的元素进行排序即可。
  • 使用 std::unordered_map 以获得更快的性能。如果您只是想查找重复项而不需要计数,请考虑使用 std::unordered_set。
  • 如果元组表示 3d 网格的顶点或 FE(有限元)网格的元素,则排序可能是违背目的的。如果这是真的,我不确定ordered_map 或任何类型的地图是否是好的用例,因为模型有更多的优化方法

标签: c++ algorithm data-structures stl


【解决方案1】:

要实现这一点,您可以在插入地图之前对其进行简单排序。

#include <bits/stdc++.h>

using namespace std;

tuple<int,int,int> additem(int a,int b,int c)
{
    int ar[3]={a,b,c};
    sort(ar,ar+3);
    return make_tuple(ar[0],ar[1],ar[2]);
}

int main()
{
    std::map<std::tuple<int, int, int>, int> faceMap;
    faceMap[additem(0,1,2)]++;
    faceMap[additem(0, 2, 1)]++;
    faceMap[additem(1, 0, 2)]++;
    faceMap[additem(1, 2, 0)]++;
    faceMap[additem(2, 1, 0)]++;
    faceMap[additem(2, 0, 1)]++;
    for(auto i:faceMap)
    {
        cout<<get<0>(i.first)<<" "<<get<1>(i.first)<<" "<<get<2>(i.first)<<" "<<i.second<<endl;
    }
    return 1;
}

输出:

0 1 2 6

【讨论】:

  • 我想我喜欢你的回答胜过喜欢我的回答。欢迎使用 StackOverflow!
  • 没有足够的新答案,所以我会在这里留下评论:我会使用std::map&lt;sorted_tuple&gt;,其中sorted_tuple 可以从std::tuple 隐式转换,那么你不能忘记拨打addItem
【解决方案2】:

考虑一下。其中vec 是您要从中查找重复项的初始元组集。

std::vector<std::tuple<int, int, int>> vec;  // your initial vector of tuples

然后找到所有重复项的可能解决方案是将您的元组转换为字符串(在将其规范化为已排序的元组之后)。然后使用ordered_map 来跟踪重复项。还有另一个从字符串到引用元组条目的映射。

std::unordered_map<std::string, int> table;
std::unordered_map<std::string, std::tuple<int, int, int>> conversionMap;

for (const auto &t : vec)
{
    std::vector<int> tmp = { std::get<0>(t), std::get<1>(t), std::get<2>(t) };
    std::sort(tmp.begin(), tmp.end());
    std::string entry = std::to_string(tmp[0]) + " " + std::to_string(tmp[1]) + " " + std::to_string(tmp[2]);
    table[entry]++;
    conversionMap[entry] = t; // or std::make_tuple(tmp[0], tmp[1], tmp[2]) if you want a sorted entry
}

上述代码的最终结果是任何给定元组三重奏的所有实例的计数都在table 映射中。使用conversionMap,它将从字符串映射回原始元组实例。

【讨论】:

    猜你喜欢
    • 2017-11-08
    • 2015-04-13
    • 2017-07-28
    • 2016-02-10
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多