【问题标题】:Custom sort based on 3 objects [duplicate]基于3个对象的自定义排序[重复]
【发布时间】:2018-07-28 09:39:42
【问题描述】:

我想根据元素与索引为 0 的元素之间的相似性对二维数组进行排序。

如何定义可以使用外部第三个对象(索引为 0 的元素)的自定义排序函数?

比较功能需要做以下事情

bool compare(float *a, float *b) {
    float *source = 2DArray[0];
    return distance(source, a) > distance(source, b);
}

调用时

std::sort(std::begin(2DArray), std::end(2DArray), compare);

显然无法访问 2DArray。

如何编写,以便对象可以调用函数来调用排序函数并授予对 2DArray[0] 的访问权限?

【问题讨论】:

  • 使用仿函数,而不是函数?
  • 2DArray 不是有效的 C++ 标识符。确保您的代码在发布之前编译(顺便问一下,2DArray 的类型是什么?)
  • 使用lambda expression 代替函数?
  • @user202729 问题没有没有指定C++标准版本,所以假设是“当前版本”,目前是C++17。因此,可以假设 lambda 是可用的。
  • @jarryd 不要发布伪代码。发布真的,可编译的代码。

标签: c++


【解决方案1】:

假设您有一些可以测量“元素之间的相似性”的函数,您可以使用 lambda 将该函数用作排序的谓词。

#include <iostream>
#include <algorithm>
#include <array>
#include <vector>

int dist2(const std::array<int, 2> &a, const std::array<int, 2> &b) {
    auto dx = a[0] - b[0];
    auto dy = a[1] - b[1];
    return dx * dx + dy * dy;
}

int main() {
    int x, y;
    std::vector<std::array<int, 2>> tab;

    while (std::cin >> x >> y) {
        tab.push_back({ x, y });
    }

    auto origin = tab.front();

    std::sort(std::begin(tab), std::end(tab), 
              [&origin](const auto &a, const auto &b) {
                  return dist2(a, origin) < dist2(b, origin);
              });

    for (const auto &a : tab) {
        std::cout << a[0] << ", " << a[1] << '\n';
    }

    return 0;
}

https://wandbox.org/permlink/5pWL2N5AOHcr20Wi

【讨论】:

  • 虽然此代码可以回答问题,但提供有关 如何 和/或 为什么 解决问题的附加上下文将改善答案的长期价值。见this meta post
  • 是的,这是一个很好的规则,但在这种情况下,我找不到可以增加价值的描述。
【解决方案2】:

因此,如果我理解正确,您想按到固定点的距离进行排序。这可能会起作用,因为该指标将为您提供“严格的弱顺序”(https://en.wikipedia.org/wiki/Weak_ordering),这是任何用于排序的比较运算符所必需的。

但是您的实际问题是:通常排序是一维的事情,因为它只是给您一个 A 小于 B 的关系,您无法轻松地将其映射到 2D。所以你需要一个关于如何线性排序你的二维结构的想法,这取决于它代表什么。 (然后你可以有一个“开始”和“结束”)

我的建议是:首先转换为一维结构,例如只需附加二维数组的所有行,然后对其进行排序。之后,您可以考虑如何在 2d 中表示它们(如果适用)。 (或者至少在您的结构上定义一维视图)

如果您详细了解您的实际问题是什么,我也许可以提供更具体的建议。

【讨论】:

    【解决方案3】:

    最简单的方法应该是像这样创建一个Comparer 类:

    struct Comparer {
        float *source;
        bool operator()(const float* a, const float* b) {
            return distance(source, a) > distance(source, b);
        } 
    };
    

    创建一个实例

    Comparer compare;
    comparer.source = 2DArray;
    

    并将其传递给std::sort:

    std::sort(std::begin(2DArray), std::end(2DArray), compare);
    

    捕获 source 指针的 lambda 函数将是更现代的方法。

    它最终或多或少相同,但捕获将被包装到编译器生成的匿名类中。

    【讨论】:

    • 剩下的问题:你仍然需要一个线性遍历顺序来定义“开始”和“结束”
    • @skeller 我没有发现问题。 std::begin()std::end() 可以很好地处理原始数组。除此之外的一切都在这里。
    • 是的,但在内部这意味着它是线性遍历的(逐行或逐列),并且生成的二维结构取决于内部遍历顺序。一般来说,在二维结构中,“下一个元素”的定义是不明确的。 (可能我对这里的细节太挑剔了)
    • @πάνταῥεῖ - 谢谢,我用 lambda 解决了它,容易多了。
    • @jarryd 如前所述,这只是一样的,只是在上面加了一点语法糖。
    猜你喜欢
    • 1970-01-01
    • 2020-07-07
    • 2015-01-23
    • 1970-01-01
    • 2018-05-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    相关资源
    最近更新 更多