ตรวจสอบว่าแผนที่มีค่าสำหรับคีย์หรือไม่?


256

วิธีที่ดีที่สุดในการตรวจสอบว่าแผนที่ STL มีค่าสำหรับคีย์ที่กำหนดคืออะไร?

#include <map>

using namespace std;

struct Bar
{
    int i;
};

int main()
{
    map<int, Bar> m;
    Bar b = {0};
    Bar b1 = {1};

    m[0] = b;
    m[1] = b1;

    //Bar b2 = m[2];
    map<int, Bar>::iterator iter = m.find(2);
    Bar b3 = iter->second;

}

ตรวจสอบสิ่งนี้ในตัวดีบักดูเหมือนว่าiterเป็นเพียงข้อมูลขยะ

หากฉันไม่แสดงข้อคิดเห็นในบรรทัดนี้:

Bar b2 = m[2]

ดีบักแสดงให้เห็นว่าเป็นb2 {i = 0}(ฉันเดาว่าหมายความว่าการใช้ดัชนีที่ไม่ได้กำหนดจะส่งคืนโครงสร้างด้วยค่าว่าง / ค่าเริ่มต้นทั้งหมดหรือไม่)

วิธีการเหล่านี้ไม่ดีเลย สิ่งที่ฉันชอบคืออินเทอร์เฟซแบบนี้:

bool getValue(int key, Bar& out)
{
    if (map contains value for key)
    {
        out = map[key];
        return true;
    }
    return false;
}

มีบางสิ่งตามสายเหล่านี้หรือไม่?


คำตอบ:


274

มีบางสิ่งตามสายเหล่านี้หรือไม่?

ไม่ด้วยคลาสแผนที่ stl คุณใช้::find()เพื่อค้นหาแผนที่และเปรียบเทียบตัววนซ้ำที่ส่งคืนstd::map::end()

ดังนั้น

map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
   //element found;
   b3 = it->second;
}

เห็นได้ชัดว่าคุณสามารถเขียนgetValue()กิจวัตรของคุณเองถ้าคุณต้องการ (เช่นใน C ++ ไม่มีเหตุผลที่จะใช้out) แต่ฉันสงสัยว่าเมื่อคุณหยุดใช้งานstd::map::find()คุณจะไม่ต้องเสียเวลา

ด้วยรหัสของคุณผิดเล็กน้อย:

m.find('2');จะค้นหาแผนที่สำหรับ KeyValue '2'ว่าเป็น IIRC คอมไพเลอร์ C ++ จะแปลง '2' เป็น int ซึ่งส่งผลให้ค่าตัวเลขสำหรับรหัส ASCII สำหรับ '2' ซึ่งไม่ใช่สิ่งที่คุณต้องการ

เนื่องจากประเภทคีย์ของคุณในตัวอย่างนี้คือintคุณต้องการค้นหาเช่นนี้:m.find(2);


7
งั้นเหรอ findบ่งบอกถึงความตั้งใจที่จะไกลได้ดีกว่าcountไม่ ยิ่งกว่าcountนั้นอย่าคืนสินค้า หากคุณอ่านคำถามของ OP เขาต้องการตรวจสอบสิ่งที่มีอยู่และส่งคืนองค์ประกอบ findทำอย่างนั้น countไม่.
อลัน

ถ้า (m.count (กุญแจ)) b3 = m [สำคัญ]; // หรืออะไรก็ตาม
pconnell

62
ฉันสงสัยอยู่เสมอว่าวัชพืชชนิดใดที่กำลังสูบบุหรี่คนที่ออกแบบ stl API ทั้งหมด
กับดัก

2
อลันฉันต้องเห็นด้วยกับ @dynamic ในเรื่องนี้การกำหนดตัววนซ้ำแล้วเปรียบเทียบกับจุดสิ้นสุดไม่ใช่วิธีธรรมชาติในการพูดว่ามีบางสิ่งไม่มีอยู่ ดูเหมือนจะตรงไปตรงมามากกว่าที่ฉันจะบอกว่าองค์ประกอบบางอย่างปรากฏขึ้นอย่างน้อยหนึ่งครั้งในแผนที่นี้ ซึ่งเป็นสิ่งที่นับไม่
PiersyP

1
@Claudiu C ++ 20 เพิ่มเพียงแค่นั้น
pooya13

330

ตราบใดที่แผนที่ไม่ใช่ Multimap หนึ่งในวิธีที่สวยงามที่สุดคือการใช้วิธีการนับ

if (m.count(key))
    // key exists

การนับจะเป็น 1 หากองค์ประกอบมีอยู่จริงในแผนที่


22
นี่จะไม่ตรวจสอบกุญแจทั้งหมดแม้ว่าจะพบกุญแจอยู่แล้ว? ที่จะได้รับอย่างรวดเร็วมีราคาแพง ...
mmdanziger

35
มันจะนับมากกว่าหนึ่งคีย์เท่านั้นหากใช้กับ Multimap
Andrew Prock

14
@mmdanziger ไม่มันไม่แพงเลย: cplusplus.com/reference/map/map/count Count มีขนาดลอการิทึม
jgyou

28
กุญแจมีอยู่แล้วอะไรนะ? ณ จุดนั้นคุณมักต้องการได้รับความคุ้มค่าโดยจ่ายสำหรับการค้นหาอื่น (เช่นใช้operator[]) findให้TryGetValueความหมายของ. NET แก่คุณซึ่งเกือบจะเป็นสิ่งที่คุณต้องการ (และเฉพาะ OP)
Ohad Schneider

2
@serine understood โปรดทราบว่าในกรณีที่คีย์หายไปในการเปิดใช้งานพฤติกรรมจะแตกต่างกันเนื่องจากแผนที่ [คีย์] จะส่งคืนค่าองค์ประกอบที่สร้างขึ้นใหม่เป็นค่าเริ่มต้น
Ohad Schneider

53

มีอยู่แล้วด้วย find ไม่เพียง แต่อยู่ในรูปแบบที่แน่นอน

if (m.find(2) == m.end() )
{
    // key 2 doesn't exist
}

หากคุณต้องการเข้าถึงค่าหากมีอยู่คุณสามารถทำได้:

map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

ด้วย C ++ 0x และอัตโนมัติไวยากรณ์ง่ายขึ้น:

auto iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

ฉันขอแนะนำให้คุณทำความคุ้นเคยกับมันมากกว่าพยายามหากลไกใหม่มาทำให้มันง่ายขึ้น คุณอาจสามารถตัดโค้ดได้เล็กน้อย แต่พิจารณาค่าใช้จ่ายในการทำเช่นนั้น ตอนนี้คุณได้แนะนำฟังก์ชั่นใหม่ที่คนคุ้นเคยกับ C ++ จะไม่สามารถจดจำได้

หากคุณต้องการใช้สิ่งนี้ต่อไปแม้จะมีคำเตือนเหล่านี้อยู่แล้ว

template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
    typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
    if (it != my_map.end() )
    {
        out = it->second;
        return true;
    }
    return false;
}

38

ฉันเพิ่งสังเกตเห็นว่าด้วยC ++ 20เราจะมี

bool std::map::contains( const Key& key ) const;

keyที่จะกลับมาจริงถ้าแผนที่ถือองค์ประกอบกับคีย์


ในที่สุดคำตอบที่พูดถึงฟังก์ชั่นนี้! (C ++ 20)
Samuel Rasquinha

ในที่สุด ขอบคุณ แต่มันเกือบ 2 ปีแล้ว! ;-)
kebs

7

amap.findส่งคืนamap::endเมื่อไม่พบสิ่งที่คุณกำลังค้นหา - คุณควรตรวจสอบสิ่งนั้น


4

ตรวจสอบค่าตอบแทนของกับfindend

map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) { 
  // contains
  ...
}

1

คุณสามารถสร้างฟังก์ชั่น getValue ของคุณด้วยรหัสต่อไปนี้:

bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
   std::map<int, Bar>::iterator foundIter = input.find(key);
   if (foundIter != input.end())
   {
      out = foundIter->second;
      return true;
   }
   return false;
}

ฉันเชื่อว่าบรรทัดที่ 6 ควรเป็นout = foundIter->second
Dithermaster

ฉันแก้ไขคำตอบของ Kip ให้แสดงอย่างถูกต้องout = foundIter->secondแทนout = *foundIter
netjeff

1

เพื่อสรุปคำตอบอื่น ๆ โดยสังเขป:

หากคุณยังไม่ได้ใช้ C ++ 20 คุณสามารถเขียนmapContainsKeyฟังก์ชันของคุณเองได้:

bool mapContainsKey(std::map<int, int>& map, int key)
{
  if (map.find(key) == map.end()) return false;
  return true;
}

หากคุณต้องการหลีกเลี่ยงการโอเวอร์โหลดจำนวนมากสำหรับmapvs unordered_mapและคีย์และประเภทค่าที่แตกต่างกันคุณสามารถทำให้templateฟังก์ชันนี้ทำงานได้

หากคุณกำลังใช้งานC++ 20หรือใหม่กว่าจะมีcontainsฟังก์ชั่นในตัว:

std::map<int, int> myMap;

// do stuff with myMap here

int key = 123;

if (myMap.contains(key))
{
  // stuff here
}

-1

หากคุณต้องการตรวจสอบว่ามีกุญแจอยู่ในแผนที่หรือไม่คุณสามารถใช้ฟังก์ชัน find () หรือ count () สมาชิกของแผนที่ ฟังก์ชั่นการค้นหาที่ใช้ที่นี่ในตัวอย่างส่งกลับตัววนซ้ำไปยังองค์ประกอบหรือแผนที่ :: สิ้นสุดมิฉะนั้น ในกรณีที่มีการนับการนับผลตอบแทนที่ 1 หากพบว่ามันจะกลับเป็นศูนย์ (หรือมิฉะนั้น)

if(phone.count(key))
{ //key found
}
else
{//key not found
}

for(int i=0;i<v.size();i++){
    phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
    if(itr!=phone.end())
        cout<<v[i]<<"="<<itr->second<<endl;
    else
        cout<<"Not found"<<endl;
}

-1

Boost multindex สามารถใช้สำหรับการแก้ปัญหาที่เหมาะสม โซลูชันต่อไปนี้ไม่ใช่ตัวเลือกที่ดีที่สุด แต่อาจมีประโยชน์ในบางกรณีที่ผู้ใช้กำหนดค่าเริ่มต้นเช่น 0 หรือ NULL เมื่อเริ่มต้นและต้องการตรวจสอบว่ามีการปรับเปลี่ยนค่าหรือไม่

Ex.
< int , string >
< string , int > 
< string , string > 

consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
       if ( it->second =="" ) 
            continue;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.