Mencoba mencari elemen minimal vektor 2D dengan lambda

Dec 10 2020

Saat ini saya mencoba menemukan elemen minimum vektor 2D. Saya mencoba berlatih menggunakan fungsi lambda C ++ 11 dan saya pikir ini mungkin praktik yang baik, tetapi sepertinya tidak bisa membuatnya dikompilasi.

Saya sadar bahwa saya dapat melakukan hal berikut:

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;

tetapi bertanya-tanya apakah hal yang sama bisa dilakukan dengan fungsi lambda. Saat ini, ini upaya terbaik saya:

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());
  });

Saya mendapatkan kesalahan: kesalahan C2672 : 'operator __surrogate_func': tidak ada fungsi kelebihan beban yang cocok ditemukan

Bagaimana saya merasa itu harus berfungsi adalah bahwa min_element luar akan melewati baris pada satu waktu (yang hanya referensi ke vektor), dari mana saya dapat mengembalikan yang terkecil, yang kemudian akan dibandingkan dengan baris lain.

Saya pikir masalahnya mungkin bahwa lambda akan menerima iterator ke vektor ints daripada referensi ke vektor ints, tetapi dereferencing tampaknya tidak membantu.

Adakah cara yang lebih baik untuk melakukan apa yang saya coba lakukan?

@assembly_wizard menunjukkan bahwa min_element menginginkan predikat yang dapat membandingkan dua item yang melewatinya. Itu dua baris. Ini mengarah ke kode berikut:

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());
});

Ini akan menemukan baris dengan elemen terkecil. Meskipun saya bisa membuatnya bekerja dengan membungkusnya di std :: min_element lain, itu menjadi jauh lebih kompleks daripada membantu dari jarak jauh. Jika ada yang punya saran yang lebih baik, saya akan senang mendengarnya!

Jawaban

2 assembly_wizard Dec 10 2020 at 08:30

Saya telah menyusun versi kerja yang melakukan apa yang saya sebutkan di komentar:

#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;
}

Lihat aksinya di atas gerendel

Ini akan mengambil minimum dari setiap baris secara terpisah, jadi kita dapatkan row_minimumsyang merupakan vektor int, dan kemudian dibutuhkan minimum ini untuk mendapatkan hasil akhir di antara semua baris.

Satu-satunya hal yang membuat kode ini lebih buruk daripada forversi loop, adalah ia menyimpan semua row_minimumsdi memori sekaligus, sebelum menjalankannya min_element. Sayangnya saya tidak tahu cara untuk melakukan ini secara bersamaan, tapi saya bukan STL terhebat yang diharapkan, jadi mungkin ada jalan.

Opsi lain yang mungkin Anda pertimbangkan adalah pertama-tama menggabungkan matriks 2D menjadi vektor 1D dan kemudian menggunakannya min_element, atau opsi yang Anda sertakan dalam pengeditan di mana Anda memanggil min_element3 kali.

Juga, jawaban SO ini tampaknya memiliki info menarik tentang solusi menggunakan boostpustaka yang mungkin lebih baik, tetapi saya tidak yakin persis apa itu.

1 Loreto Dec 10 2020 at 14:52

Sedikit lebih sederhana: Dengan std :: for_each Anda melakukan iterasi pada setiap vektor dalam matriks, dan mendapatkan elemen minimumnya. Seperti minyang ditangkap oleh referensi, Anda mendapatkan min dari semuanya.

#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;
}