#c
#c
Вопрос:
У меня есть набор, в котором я хочу найти элементы в нем. Прямо сейчас у меня есть глобальные объекты, которые я использую для хранения своих находок — (ItemSetMap allMusicByBand)
Я хотел бы уйти от этого и просто выполнить поиск по наборам напрямую.
Вся информация о компакт-диске хранится в закрытом разделе — (ItemSet allCDS;)
вот library.cpp —
в прокомментированном коде я выполнял поиск и добавлял к глобальному объекту…
Вместо этого я хотел бы выполнить поиск в функции musicByBand..
#include "Library.h"
#include "book.h"
#include "cd.h"
#include "dvd.h"
#include <iostream>
//ItemSetMap allBooksByAuthor; //these are what i am trying to get away from...
ItemSetMap allmoviesByDirector;
ItemSetMap allmoviesByActor;
//ItemSetMap allMusicByBand;
ItemSetMap allMusicByMusician;
const Item* Library::addMusicCD(const stringamp; title, const stringamp; band, const int nSongs)
{
CD* item = new CD(title,band,nSongs);
allCDS.insert(item);
//ItemSetMap::iterator myband = allMusicByBand.find(band);
//if(myband != allMusicByBand.end())
//{
//myband->second->insert(item);
//}
//else{
//ItemSet* obj = new ItemSet();
//obj->insert(item);
//allMusicByBand.insert(make_pair(band, obj));
//}
return item;
}
const ItemSet* Library::musicByBand(const stringamp; band) const
{
return allMusicByBand[author];
}
надеюсь, я достаточно ясно объяснил, чего я хотел.
Я попытался выполнить итерацию по нему. Я перепробовал практически все, что смог придумать.. Класс CD является суперклассом класса item.
Спасибо..
Ответ №1:
«Идиоматическим» способом сделать это может быть использование алгоритма std::remove_copy_if . Это выглядело бы примерно так:
class NotMatching {
string bandName_;
public:
NotMatching( const stringamp; band ) : bandName_( band ) {}
bool operator()( const Itemamp; item ) {
return item.bandName() != bandName_;
}
};
const ItemSet musicByBand(const stringamp; band)
{
ItemSet matchingItems;
std::remove_copy_if( allCDS.begin(), allCDS.end(),
insert_iterator< ItemSet >( matchingItems, matchingItems.begin() ),
NotMatching( band ) );
return matchingItems;
}
Но, честно говоря, я думаю, что подход Тайлера проще и понятнее.
Ответ №2:
Самый простой способ сделать это был бы такой:
const ItemSet* Library::musicByBand(const stringamp; band) const
{
ItemSet* bandMusic = new ItemSet();
for (ItemSet::const_iterator i = allCDs.begin(); i != allCDs.end(); i)
{
if ((*i)->getBand() == band) {
bandMusic->insert(*i);
}
}
return itemSet;
}
Хотя это выполняется за O (n) раз, что совсем не использует тот факт, что вы используете set . С тем же успехом они могли бы быть в векторе. Способ, которым вы делали это раньше с наборами «index», на самом деле является более быстродействующим решением, хотя для этого потребуется несколько больше памяти. Кроме того, предположительно, методы извлечения будут вызываться гораздо чаще, чем методы вставки, поэтому имеет смысл проделать больше работы над вставкой, чтобы сэкономить на работе во время извлечения. Но, конечно, если вы сделаете это, вы захотите, чтобы наборы индексов были закрытыми элементами, а не глобальными.
Вы также должны быть очень осторожны при управлении памятью здесь. Меня беспокоит тот факт, что вы возвращаете постоянный указатель на ItemSet
из musicByBand
метода. Почему это не может быть просто ItemSet
то, что вы возвращаете?
Комментарии:
1. спасибо — мне пришлось привести класс CD, поскольку он является суперклассом item
2. Лучшим способом справиться с этим было бы сделать
allCDs
быть наборомCD*
, а не наборомItem*
. Это также привело бы к введению во время компиляции ограничения на то, что вещи, которых нет,CDs
не попадают вallCDs
набор.
Ответ №3:
Это пример кода, который использует функтор с std::find_if
алгоритмом для поиска определенного элемента в set
struct BandComparison : public std::binary_function<Item*, std::string, bool>
{
public:
bool operator()(Item* pItem, const std::stringamp; bandName) const
{
bool equal = false;
CD* pCD = dynamic_cast<CD*>(pItem);
if(pCD)
{
equal = pCD->getBand() == bandName;
}
return equal;
}
};
void Library::addCD(const std::string amp;band)
{
//First check whether CD with this band name exists
ItemSet::iterator iter = std::find_if(m_cds.begin(), m_cds.end(), std::bind2nd(BandComparison(), band));
if(iter == m_cds.end())
{
m_cds.insert(new CD(band));
}
}
Комментарии:
1. Обратите внимание, что это более правильно объектно-ориентированный подход, чем то, что я написал, но он ничуть не быстрее.
2. Да, я согласен. На самом деле, я ненавижу эти функторы со связующими. Это можно написать гораздо более элегантно, используя
boost
. Но я подумал о том, чтобы не использоватьboost
здесь, поскольку OP, похоже, не использует его.