Cara menemukan jika kunci yang diberikan ada di C ++ std :: map

450

Saya mencoba memeriksa apakah kunci yang diberikan ada di peta dan agak tidak bisa melakukannya:

typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here

jadi bagaimana saya bisa mencetak apa yang ada di p?

Tidak ada yang bisa kita lakukan
sumber
std::pair<iterator,bool> insert( const value_type& value );Apa bool itu kembali? apakah itu memberitahu, jika kuncinya sudah ada atau tidak?
krithikaGopalakrisnan

Jawaban:

691

Menggunakan map::find

if ( m.find("f") == m.end() ) {
  // not found
} else {
  // found
}

sumber
105
Jika Anda hanya ingin memeriksa apakah ada kunci tertentu, Anda mungkin lebih suka menggunakanmap::count
tomsmeding
10
@tomsmeding Hanya ada satu kunci di std :: map. Jadi hitungannya bisa 0 atau 1. Apakah yang satu lebih efisien daripada yang lain?
goelakash
34
@goelakash tidak; hanya saja countmengembalikan intsementara findmengembalikan seluruh iterator. Anda menyimpan konstruksi iterator :) Jelas, jika Anda kemudian akan menggunakan nilai jika ada, gunakan temukan dan simpan hasilnya.
tommeding
9
@tommeding Jika Anda menggunakan multimap, Anda harus melihat seluruh wadah. Dalam hal ini, find () mungkin lebih cepat.
Trevor Hickey
11
Bagi mereka yang mencari kecepatan: count dan kecepatannyafind hampir identik saat menggunakan peta yang membutuhkan kunci unik. (1) Jika Anda tidak memerlukan elemen untuk mempertahankan urutan tertentu, gunakan std :: unordered_map , yang memiliki pencarian hampir konstan dan dapat sangat bermanfaat saat menyimpan lebih dari beberapa pasangan. (2) Jika Anda ingin menggunakan nilai jika ada, simpan hasil :: find dan gunakan iterator untuk mencegah 2 pencarian:auto it = m.find("f"); if (it != m.end()) {/*Use it->second*/}
cdgraham
305

Untuk memeriksa apakah kunci tertentu di peta ada, gunakan countfungsi anggota dalam salah satu cara berikut:

m.count(key) > 0
m.count(key) == 1
m.count(key) != 0

The dokumentasi untuk map::findmengatakan: "fungsi anggota lain, map::count, dapat digunakan untuk hanya memeriksa apakah kunci tertentu ada."

The dokumentasi untuk map::countmengatakan: "Karena semua elemen dalam wadah peta yang unik, fungsi hanya dapat kembali 1 (jika unsur ini ditemukan) atau nol (jika tidak)."

Untuk mengambil nilai dari peta melalui kunci yang Anda tahu ada, gunakan peta :: di :

value = m.at(key)

Tidak seperti map :: operator [] , map::attidak akan membuat kunci baru di peta jika kunci yang ditentukan tidak ada.

DavidRR
sumber
33
Jika Anda akan melakukan kedua operasi, periksa apakah ada dan kemudian lakukan sesuatu. Gunakan findsebagai gantinya. The secondatribut dari iterator dikembalikan oleh finddapat digunakan mengambil nilai dari kunci. Jika Anda menggunakan countitu atatau operator[]Anda melakukan dua operasi ketika Anda bisa menggunakan hanya satu.
OdraEncoded
1
Anda tidak perlu melakukan> 0, == 1 atau! = 0; itu adalah pemeriksaan tepat yang dilakukan C ++ dalam pernyataan if (kondisi! = 0), jadi Anda bisa menggunakanif(m.count(key))
jv110
6
@ jv110 Kompiler Microsoft C ++ mengeluarkan peringatan ketika bertemu para pemain dari intke bool. Meskipun ada kompiler C ++ lainnya yang tidak mengeluarkan peringatan serupa, saya lebih suka menggunakan perbandingan eksplisit untuk membuat maksudnya jelas dan meningkatkan keterbacaan. Perhatikan bahwa bahasa lain seperti C # melarang konversi tersirat untuk mencegah kemungkinan memperkenalkan kesalahan pemrograman halus.
DavidRR
apa kompleksitas waktu penghitungan? Apakah hanya operasi O (1)?
Mazeryt
1
@ Mazeryt Mengingat bahwa kita berbicara tentang kelas di perpustakaan standar C ++, saya pasti akan berasumsi begitu. Untuk diskusi bahasa-agnostik dari pertanyaan Anda, lihat Dapatkah tabel hash benar-benar menjadi O (1)? .
DavidRR
47

C ++ 20 memberi kita std::map::containsuntuk melakukan itu.

#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<int, std::string> example = {{1, "One"}, {2, "Two"}, 
                                     {3, "Three"}, {42, "Don\'t Panic!!!"}};

    if(example.contains(42)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Not found\n";
    }
}
Denis Sablukov
sumber
34
Saya kira saya akan mengatakannya: Akhirnya.
Erik Campobadal
2
Tentang waktu .....
Ridhuvarshan
39

Anda bisa menggunakan .find():

map<string,string>::iterator i = m.find("f");

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
Thomas Bonini
sumber
15
m.find == m.end() // not found 

Jika Anda ingin menggunakan API lain, cari cari m.count(c)>0

 if (m.count("f")>0)
      cout << " is an element of m.\n";
    else 
      cout << " is not an element of m.\n";
aJ.
sumber
12

Saya pikir kamu mau map::find. Jika m.find("f")sama dengan m.end(), maka kuncinya tidak ditemukan. Jika tidak, temukan kembalikan iterator yang menunjuk ke elemen yang ditemukan.

Kesalahan ini karena p.firstmerupakan iterator, yang tidak berfungsi untuk penyisipan aliran. Ubah baris terakhir Anda ke cout << (p.first)->first;. padalah sepasang iterator, p.firstadalah iterator, p.first->firstadalah kunci string.

Peta hanya dapat memiliki satu elemen untuk kunci yang diberikan, jadi equal_rangetidak terlalu berguna. Ini ditentukan untuk peta, karena itu ditentukan untuk semua wadah asosiatif, tetapi jauh lebih menarik untuk multimap.

Steve Jessop
sumber
Sebenarnya, karena itu adalah sepasang iterator ke peta, itu harus "cout << p.first-> pertama;"
stefaanv
Saya sudah memperbaiki jawaban saya, terima kasih. Itulah yang saya dapatkan karena tidak mengkompilasi kode saya. Dan Anda benar (dalam komentar yang dihapus) tentang memeriksa validitas, tetapi saya hanya mencoba menjelaskan mengapa dia tidak dapat mencetak hal.pertama, dan itu bukan karena itu tidak valid - kita tahu "f" akan ditemukan. Karena saya tidak merekomendasikan menggunakan equal_range sama sekali, saya tidak akan menunjukkan kode pemeriksaan kesalahan untuk itu.
Steve Jessop
Wow, Anda benar-benar memindai SO. Saya baru saja menambahkannya untuk kelengkapan, karena poin Anda jelas. Saya menambahkan cek validitas ke jawaban saya sebelumnya, tetapi jawaban Anda mengalahkan saya, jadi saya menghapusnya, karena tidak menambahkan sebanyak itu, seperti yang Anda sebutkan.
stefaanv
Ya, saya hanya melihatnya sama sekali karena komentar Anda muncul ketika saya memposting komentar saya.
Steve Jessop
12

C++17disederhanakan ini sedikit lebih banyak dengan If statement with initializer. Dengan cara ini Anda dapat memiliki kue dan memakannya juga.

if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
{
    // Use `structured binding` to get the key
    // and value.
    auto[ key, value ] { *it };

    // Grab either the key or value stored in the pair.
    // The key is stored in the 'first' variable and
    // the 'value' is stored in the second.
    auto mkey{ it->first };
    auto mvalue{ it->second };

    // That or just grab the entire pair pointed
    // to by the iterator.
    auto pair{ *it };
} 
else 
{
   // Key was not found..
}
WBuck
sumber
4
map<string, string> m;

periksa kunci ada atau tidak, dan kembalikan jumlah yang terjadi (0/1 di peta):

int num = m.count("f");  
if (num>0) {    
    //found   
} else {  
    // not found  
}

periksa kunci ada atau tidak, dan kembalikan iterator:

map<string,string>::iterator mi = m.find("f");  
if(mi != m.end()) {  
    //found  
    //do something to mi.  
} else {  
    // not found  
}  

dalam pertanyaan Anda, kesalahan yang disebabkan oleh buruk operator<<yang berlebihan, karena p.firstini map<string, string>, Anda tidak dapat mencetak keluar. coba ini:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}
hustljian
sumber
1
Anda salah ketik. Ubah "cout" menjadi "count"
Rivka
1
Dan kesalahan ketik itu dapat benar-benar membuat seseorang coutcount
kesal
4
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

Tentu saja jika Anda ingin menjadi pelamun Anda selalu bisa templat keluar fungsi yang juga mengambil fungsi ditemukan dan fungsi tidak ditemukan, seperti ini:

template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
    auto& it = container.find(key);
    if (it != std::end(container))
    {
        found_function(key, it->second);
    }
    else
    {
        not_found_function(key);
    }
}

Dan gunakan seperti ini:

    std::map<int, int> some_map;
    find_and_execute(some_map, 1,
        [](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
        [](int key){ std::cout << "key " << key << " not found" << std::endl; });

Kelemahan dari ini adalah datang dengan nama yang bagus, "find_and_execute" canggung dan saya tidak dapat menemukan sesuatu yang lebih baik dari atas kepala saya ...

Lambage
sumber
3

Hati-hati dalam membandingkan hasil pencarian dengan akhir seperti untuk peta 'm' karena semua jawaban telah dilakukan di atas peta :: iterator i = m.find ("f");

 if (i == m.end())
 {
 }
 else
 {
 }  

Anda tidak boleh mencoba dan melakukan operasi apa pun seperti mencetak kunci atau nilai dengan iterator i jika sama dengan m.end () jika tidak maka akan menyebabkan kesalahan segmentasi.

Invictus
sumber
0

Membandingkan kode std :: map :: find dan std :: map :: count, saya katakan yang pertama dapat menghasilkan beberapa keuntungan kinerja:

const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
    const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
    return (_Where == end()
        || _DEBUG_LT_PRED(this->_Getcomp(),
            _Keyval, this->_Key(_Where._Mynode()))
                ? end() : _Where);
    }

size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
    _Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
    size_type _Num = 0;
    _Distance(_Ans.first, _Ans.second, _Num);
    return (_Num);
    }
Berharap
sumber
0

Saya tahu pertanyaan ini sudah memiliki beberapa jawaban yang baik tetapi saya pikir solusi saya layak untuk dibagikan.

Ia bekerja untuk keduanya std::mapdan std::vector<std::pair<T, U>>dan tersedia dari C ++ 11.

template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
    using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;

    auto search_result = std::find_if(
        first, last,
        [&key](ValueType const& item) {
            return item.first == key;
        }
    );

    if (search_result == last) {
        return false;
    } else {
        return true;
    }
}
Alat pemecah buah keras
sumber
-5

Jika Anda ingin membandingkan pasangan peta, Anda dapat menggunakan metode ini:

typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;

controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
    TestMap::iterator it;
    it = testMap.find(x);

    if (it->second == y)
    {
        cout<<"Given value is already exist in Map"<<endl;
    }
}

Ini adalah teknik yang berguna.

EmreS
sumber
Sebagai pemula dengan pemrograman C ++, saya benar-benar ingin tahu mengapa jawaban ini diturunkan. Mengapa jawaban ini tidak populer?
gromit190
3
@ gromit190 karena menggunakan seluruh struktur data lain untuk melihat apakah kunci ada ketika std :: map sudah memiliki kemampuan ini. Ini juga akan memerlukan sinkronisasi antara dua struktur data yang merupakan ketergantungan yang tidak seorang pun ingin berurusan dengan.
Lambage
-5
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }
Muhammad Ahmad Zafar
sumber
3
Harap uraikan kode Anda. Cuplikan tanpa penjelasan apa pun cenderung tidak membantu dalam jangka panjang.
iBug