람다로 2D 벡터의 최소 요소 찾기

Dec 10 2020

현재 2D 벡터의 최소 요소를 찾으려고합니다. C ++ 11 람다 함수를 사용하여 연습하려고하는데 이것이 좋은 방법이라고 생각했지만 컴파일 할 수없는 것 같습니다.

다음을 수행 할 수 있다는 것을 알고 있습니다.

vector<vector<int>> matrix = {
                                {1, 2, 3, 4, 5 },
                                {6, 7, 8, 9, 10 },
                                {5, 6, 8, 1, 12 },
                                {1, 7, 2, 4, 18 },
};

int result = std::numeric_limits<int>::max();
for(const auto& row : matrix)
{
  int minElemInRow = *std::min_element(row.begin(), row.end());
  result = std::min(result , minElemInRow);
}
return result;

하지만 람다 함수로 똑같이 할 수 있는지 궁금합니다. 현재 이것이 최선의 시도입니다.

vector<vector<int>> matrix = {
                                {1, 2, 3, 4, 5 },
                                {6, 7, 8, 9, 10 },
                                {5, 6, 8, 1, 12 },
                                {1, 7, 2, 4, 18 },
};

return *std::min_element(matrix.begin(), matrix.end(), 
  [](const auto& row)
  {
    return *std::min_element(row.begin(), row.end());
  });

오류가 발생합니다. 오류 C2672 : 'operator __surrogate_func': 일치하는 오버로드 된 함수가 없습니다.

작동해야한다고 생각하는 방식은 외부 min_element가 한 번에 한 행 (벡터에 대한 참조 일뿐)을 전달하여 가장 작은 값을 반환 한 다음 다른 행과 비교할 수 있다는 것입니다.

문제는 람다가 int 벡터에 대한 참조가 아닌 int 벡터에 대한 반복자를 수신하는 것일 수 있지만 역 참조가 도움이되지 않는 것 같습니다.

내가하려는 일을하는 더 좋은 방법이 있습니까?

@assembly_wizard는 min_element가 전달 된 항목 중 두 개를 비교할 수있는 조건자를 원한다고 지적했습니다. 그것은 두 줄입니다. 이로 인해 다음 코드가 생성됩니다.

vector<vector<int>> matrix = {
                                {1, 2, 3, 4, 5 },
                                {6, 7, 8, 9, 10 },
                                {5, 6, 8, 1, 12 },
                                {1, 7, 2, 4, 18 },
};

auto i = std::min_element(matrix.begin(), matrix.end(),
        [](const auto& lhs, const auto& rhs)
{
        return *std::min_element(lhs.begin(), lhs.end()) <
            *std::min_element(rhs.begin(), rhs.end());
});

가장 작은 요소가있는 행을 찾습니다. 다른 std :: min_element로 래핑하여 작업을 수행 할 수 있지만 원격으로 도움이되는 것보다 훨씬 복잡해지고 있습니다. 누구든지 더 나은 제안이 있으면 듣고 싶습니다!

답변

2 assembly_wizard Dec 10 2020 at 08:30

주석에서 언급 한 작업을 수행하는 작업 버전을 컴파일했습니다.

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

int main() {
    std::vector<std::vector<int>> matrix = {
        {1, 2, 3, 4, 5 },
        {6, 7, 8, 9, 10 },
        {5, 6, 8, 1, 12 },
        {1, 7, 2, 4, 18 },
    };

    std::vector<int> row_minimums(matrix.size());
    std::transform(matrix.begin(), matrix.end(), row_minimums.begin(), [](const auto& row) {
        return *std::min_element(row.begin(), row.end());
    });
    auto i = *std::min_element(row_minimums.begin(), row_minimums.end());

    std::cout << "Minimum element is: " << i << std::endl;
}

Godbolt에서 실제로 확인하십시오.

이것은 각 행의 최소값을 개별적으로 취하므로 row_minimums정수 벡터를 얻은 다음 모든 행 사이의 최종 결과를 얻기 위해 최소값을 취합니다.

이 코드를 for루프 버전 보다 더 나쁘게 만드는 유일한 방법 은 row_minimums실행하기 전에 모든 것을 한 번에 메모리에 보관한다는 min_element것입니다. 불행히도 나는 이것을 동시에 수행하는 방법을 모르지만 STL이 기대하는 가장 큰 것은 아니므로 방법이있을 수 있습니다.

고려할 수있는 다른 옵션은 먼저 2D 행렬을 1D 벡터로 연결 한 다음이를 사용 min_element하거나 편집에 포함 된 옵션을 min_element3 번 호출하는 것 입니다.

또한 이 SO 답변 에는 boost라이브러리를 사용하는 솔루션에 관한 흥미로운 정보가있는 것 같습니다 .하지만 그것이 무엇인지 정확히 모르겠습니다.

1 Loreto Dec 10 2020 at 14:52

좀 더 간단합니다. std :: for_each를 사용하면 행렬의 각 벡터를 반복하고 최소 요소를 얻습니다. min참조로 캡처 한대로 모두의 최소값을 얻습니다.

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

int main() {
    std::vector<std::vector<int>> matrix = {
        {1, 2, 3, 4, 5 },
        {6, 7, 8, 9, 10 },
        {5, 6, 8, 1, 12 },
        {1, 7, 2, 4, 18 },
    };

    int min = std::numeric_limits<int>::max();

    std::for_each(matrix.begin(), matrix.end(), 
        [&min](const auto& v) 
        { 
           min = std::min(*min_element(v.begin(), v.end()), min);
        }
    );

    std::cout << "Minimum element is: " << min << std::endl;
}