我有一个std::vector<PLY>
,其中包含许多结构:
struct PLY {
int x;
int y;
int greyscale;
}
某些PLY在位置x
和y
方面可能重复,但不一定就其greyscale
值而言。找到那些(位置)重复项并用单个PLY
实例替换它们的最佳方法是什么,该实例具有表示所有重复项的平均灰度的灰度值?
例如:PLY a{1,1,188}
是PLY b{1,1,255}
的副本。相同(x,y)位置可能是不同的灰度。
答案 0 :(得分:4)
根据您对Ply
的描述,您需要这些运算符:
auto operator==(const Ply& a, const Ply& b)
{
return a.x == b.x && a.y == b.y;
}
auto operator<(const Ply& a, const Ply& b)
{
// whenever you can be lazy!
return std::make_pair(a.x, a.y) < std::make_pair(b.x, b.y);
}
非常重要:如果定义&#34;两个Ply
如果他们的x
和y
完全相同&#34;不是一般有效,然后定义忽略greyscale
的比较运算符是一个不好的ideea。在这种情况下,您应该定义单独的函数对象或非运算符函数,并将它们传递给函数。
有一个很好的经验法则,一个函数不应该只有一个循环。因此,我们定义了这个辅助函数,而不是嵌套的2 for
循环,它计算连续重复的平均值,并返回连续重复范围的结尾:
// prereq: [begin, end) has at least one element
// i.e. begin != end
template <class It>
auto compute_average_duplicates(It begin, It end) -> std::pair<int, It>
// (sadly not C++17) concepts:
//requires requires(It i) { {*i} -> Ply; }
{
auto it = begin + 1;
int sum = begin->greyscale;
for (; it != end && *begin == *it; ++it) {
sum += it->greyscale;
}
// you might need rounding instead of truncation:
return std::make_pair(sum / std::distance(begin, it), it);
}
有了这个,我们可以得到我们的算法:
auto foo()
{
std::vector<Ply> v = {{1, 5, 10}, {2, 4, 6}, {1, 5, 2}};
std::sort(std::begin(v), std::end(v));
for (auto i = std::begin(v); i != std::end(v); ++i) {
decltype(i) j;
int average;
std::tie(average, j) = compute_average_duplicates(i, std::end(v));
// C++17 (coming soon in a compiler near you):
// auto [average, j] = compute_average_duplicates(i, std::end(v));
if (i + 1 == j)
continue;
i->greyscale = average;
v.erase(i + 1, j);
// std::vector::erase Invalidates iterators and references
// at or after the point of the erase
// which means i remains valid, and `++i` (from the for) is correct
}
}
答案 1 :(得分:1)
您可以先应用词典排序。在排序过程中,您应该注意溢出greyscale
。使用当前的方法,您将有一些舍入误差,但它会很小,因为我首先求和,然后才是平均值。
在第二部分中,您需要从数组中删除重复项。我使用了额外的索引数组来复制每个元素不超过一次。如果您对x
,y
或greyscale
有一些禁用值,则可以使用它,因此可以在没有其他数组的情况下相处。
struct PLY {
int x;
int y;
int greyscale;
};
int main()
{
struct comp
{
bool operator()(const PLY &a, const PLY &b) { return a.x != b.x ? a.x < b.x : a.y < b.y; }
};
vector<PLY> v{ {1,1,1}, {1,2,2}, {1,1,2}, {1,3,5}, {1,2,7} };
sort(begin(v), end(v), comp());
vector<bool> ind(v.size(), true);
int s = 0;
for (int i = 1; i < v.size(); ++i)
{
if (v[i].x == v[i - 1].x &&v[i].y == v[i - 1].y)
{
v[s].greyscale += v[i].greyscale;
ind[i] = false;
}
else
{
int d = i - s;
if (d != 1)
{
v[s].greyscale /= d;
}
s = i;
}
}
s = 0;
for (int i = 0; i < v.size(); ++i)
{
if (ind[i])
{
if (s != i)
{
v[s] = v[i];
}
++s;
}
}
v.resize(s);
}
答案 2 :(得分:0)
所以你需要检查,PLY a1 { 1,1,1 };
是否重复PLY a2 {2,2,1};
如此简单的方法是覆盖operator ==
以检查a1.x == a2.x
和a1.y == a2.y
。在您可以编写自己的函数removeDuplicates(std::vector<PLU>& mPLY);
之后,将使用此向量的迭代器,进行比较和删除。但如果你想过于频繁地从数组中间删除,最好使用std::list
。