【问题标题】:Find values which are repeated exactly once in a vector查找向量中仅重复一次的值
【发布时间】:2020-04-11 00:22:43
【问题描述】:

我有一个四面体网格作为点向量 (std::array<double, 3>) 和四面体向量 (std::array<int, 4>)。我想检查一个特定的顶点是否属于网格的边界。

为此,每个四面体定义了 4 个面([0,1,2]、[0,1,3]、[1,2,3] 和 [0,2,3])。面 [0,1,2] 被认为与面 [0,2,1] 或任何其他排列相等。如果一个面在所有网格中只存在一次,那么它就是一个边界。内部面出现两次。如果顶点属于边界面,则顶点是边界。

我的计划是创建一个包含所有面孔的向量 (std::array<int, 3>),然后删除出现两次的条目。如果它们出现两次,我想删除这两个条目,而不仅仅是重复的条目。此外,相等比较器必须能够检测两个面是否相等,同时考虑到可能的排列。

我不确定如何进行此操作,或者是否存储包含所有面的向量然后删除元素是最佳解决方案。任何想法都会非常有帮助。

【问题讨论】:

  • 你能改变点向量中值的顺序吗?如果你能做到这一点,那么你就不需要处理排列。
  • 其实,我可以。这样可以避免使用自定义比较器

标签: c++ containers unique


【解决方案1】:

这一切都归结为创建比较函数,将容器中值的排列视为相等。

这样做的概念是:

  • 将容器中的值复制到std::vector
  • 然后对std::vectors进行排序
  • 然后使用std::vector 中现有的比较功能

作为示例,我创建了一个通用 lambda 来执行此任务。请看:

auto cmpPermLess = [](const auto& c1, const auto& c2) -> bool { 
    std::vector v1(c1.begin(), c1.end());
    std::vector v2(c2.begin(), c2.end());
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());
    return v1 < v2;
};

类似的方法也可以用于其他比较。

当然,您也可以定义简单的其他运算符重载或比较函数。但是机制总是一样的。将参数复制到std::vectors,然后排序,再对比std::vectors

现在我将展示一些驱动程序代码来测试所有这些:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
#include <array>
#include <iterator>

// A generic Lambda for comparing containers and ignoring permutations
// Less than
auto cmpPermLess = [](const auto& c1, const auto& c2) -> bool { std::vector v1(c1.begin(), c1.end());
    std::vector v2(c2.begin(), c2.end());
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());
    return v1 < v2;
};
// Equal 
auto cmpPermEqual = [](const auto& c1, const auto& c2) -> bool {    std::vector v1(c1.begin(), c1.end());
    std::vector v2(c2.begin(), c2.end());
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());
    return v1 == v2;
};

// Example for Face definition
using Face = std::array<int, 3>;

// Example for a less than operator for Face
bool operator<(const Face& f1, const Face& f2) { return cmpPermLess(f1, f2); };

// Some test code for syntax check.
int main() {

    // Define a vector with Faces
    std::vector<Face> vf{ {0,1,2},{0,1,3},{1,2,0},{3,1,0},{1,2,3},{0,3,1},{1,3,0}};

    std::cout << "\n\nOriginal Vector:\n";
    for (const Face& f : vf) std::cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n';

    // And some standalong faces
    Face f1{ 2,1,0 }, f2{ 0,1,3 };

    // Check less than operator 
    if (f1 < f2) {
        std::cout << "\n\nF1 is less then F2\n";
    }

    // Check comparator for usage in algorithms
    std::sort(vf.begin(), vf.end(), cmpPermLess);

    std::cout << "\n\nSorted vector:\n";
    for (const Face& f : vf) std::cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n';


    // And check COmparator for usage in other containers
    std::set<Face, decltype(cmpPermLess)> sf(vf.begin(),vf.end());

    std::cout << "\n\nSet with unique elements:\n";
    for (const Face& f : sf) std::cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n';

    // Check comparator for usage in algorithms
    std::sort(vf.begin(), vf.end(), cmpPermLess);

    std::cout << "\n\nSorted vector:\n";
    for (const Face& f : vf) std::cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n';

    // Now the vector is sorted. Search doubles and delete them
    for (std::vector<Face>::iterator it = std::adjacent_find(vf.begin(), vf.end(), cmpPermEqual); 
        it != vf.end(); 
        it = std::adjacent_find(vf.begin(), vf.end(), cmpPermEqual)) {

            vf.erase(it, it + 2);
    }

    std::cout << "\n\nDoubles eliminated:\n";
    for (const Face& f : vf) std::cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n';

    return 0;
};

最后,在函数main 中,您还将看到我们如何消除双打。而且,他们俩。我们对向量进行排序,然后使用std::adjacent_find,看看我们是否有两个双打,一个在另一个之下。如果是这样,我们将它们都删除。我们重复这个,直到不再有双打为止。

【讨论】:

  • cmpPermLess 和 cmpPermEqual 是用来检测两个排列是否相等,对吧?我打算为此使用 is_permutation 。由于您要为两个 Faces (array) 重载 operator,对吧?
  • 是的,你是对的。这种方法消除了排列。它将 2 个排列视为相等。是的,再次正确,您需要比较“苹果与苹果”
  • 其实没有这段代码是有问题的。它适用于我最多只有 2 个元素的情况,但对于 3 个或更多数量的偶数元素会失败。您可以出于文档目的对其进行更新吗?
猜你喜欢
  • 2020-10-20
  • 1970-01-01
  • 2017-11-03
  • 2015-07-04
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多