2016-03-15 3 views
0

У меня есть такой код.Как найти товар в векторе?

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <vector> 
#include <functional> 

using namespace std; 

class A 
{ 
    public: 
     A(int iVal) : _val(iVal) {} 
     int getVal() const { return _val; } 
    private: 
     int _val; 
}; 

class B 
{ 
    public: 
     B(int iNum) : _num(iNum) {} 
     int getNum() const { return _num; } 
    private: 
     int _num; 
}; 

bool isInVecA(vector<A> vectorA, int iVal) 
{ 
    for(vector<A>::const_iterator it=vectorA.begin(); it != vectorA.end(); it++) 
    { 
     if(it->getVal() == iVal) 
      return true; 
    } 
    return false; 
} 

bool isInVecB(vector<B> vectorB, int iNum) 
{ 
    for(vector<B>::const_iterator it=vectorB.begin(); it != vectorB.end(); it++) 
    { 
     if(it->getNum() == iNum) 
      return true; 
    } 
    return false; 
} 

int main() 
{  
    A arrayA[] = { A(1), A(2), A(3) }; 
    vector<A> vectorA(arrayA, arrayA + sizeof(arrayA)/sizeof(A)); 

    B arrayB[] = { B(3), B(4), B(5) }; 
    vector<B> vectorB(arrayB, arrayB + sizeof(arrayB)/sizeof(B)); 

    int key = 3; 

    if(isInVecA(vectorA, key) && isInVecB(vectorB, key)) 
     cout << "Key " << key << " is in both vectors." << endl; 
    else 
     cout << "Key " << key << " is not in both vectors." << endl; 

    return 0; 
} 

То, что я хочу сделать, это просто создать что-то, чтобы заменить функцию isInVecA и isInVecB, поскольку они слишком похожи. Предположим, I не может изменить класс A и класс B.


спасибо, каждый. Я совершенно новый для StackOverflow. Не знаю, где разместить решение, с которым мы с моим другом придумаем. Поэтому я выразился здесь.

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <vector> 
#include <functional> 
#include <boost/bind.hpp> 

using namespace std; 

class A 
{ 
    public: 
     A(int iVal) : _val(iVal) {} 
     int getVal() const { return _val; } 
    private: 
     int _val; 
}; 

class B 
{ 
    public: 
     B(int iNum) : _num(iNum) {} 
     int getNum() const { return _num; } 
    private: 
     int _num; 
}; 

template<typename T> 
bool isInVec(vector<T> vec, int (T::*func)() const, int iVal) 
{ 
    return find_if(vec.begin(), vec.end(), boost::bind(func, _1) == iVal) != vec.end(); 
} 

int main() 
{  
    A arrayA[] = { A(1), A(2), A(3) }; 
    vector<A> vectorA(arrayA, arrayA + sizeof(arrayA)/sizeof(A)); 

    B arrayB[] = { B(3), B(4), B(5) }; 
    vector<B> vectorB(arrayB, arrayB + sizeof(arrayB)/sizeof(B)); 

    int key = 3; 

    if(isInVec<A>(vectorA, &A::getVal, key) && isInVec<B>(vectorB, &B::getNum, key)) 
     cout << "Key " << key << " is in both vectors." << endl; 
    else 
     cout << "Key " << key << " is not in both vectors." << endl; 

    return 0; 
} 
+5

Посмотрите на 'станд :: find_if'. – Jarod42

ответ

1

Вы можете создать компаратор и использовать std::find_if.

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <vector> 
#include <functional> 

using namespace std; 

class A 
{ 
    public: 
     A(int iVal) : _val(iVal) {} 
     int getVal() const { return _val; } 
    private: 
     int _val; 
}; 

class B 
{ 
    public: 
     B(int iNum) : _num(iNum) {} 
     int getNum() const { return _num; } 
    private: 
     int _num; 
}; 

class cmpA 
{ 
    private: 
     int target; 
    public: 
     cmpA(int t) : target(t) {} 
     bool operator()(const A& a) const { 
      return a.getVal() == target; 
     } 
}; 
class cmpB 
{ 
    private: 
     int target; 
    public: 
     cmpB(int t) : target(t) {} 
     bool operator()(const B& b) const { 
      return b.getNum() == target; 
     } 
}; 

template<class T, class V> 
bool isInVec(const vector<V>& vector, int iNum) 
{ 
    return find_if(vector.begin(), vector.end(), T(iNum)) != vector.end(); 
} 

int main(void) { 
    A arrayA[] = { A(1), A(2), A(3) }; 
    vector<A> vectorA(arrayA, arrayA + sizeof(arrayA)/sizeof(A)); 

    B arrayB[] = { B(3), B(4), B(5) }; 
    vector<B> vectorB(arrayB, arrayB + sizeof(arrayB)/sizeof(B)); 

    int key = 3; 

    if(isInVec<cmpA>(vectorA, key) && isInVec<cmpB>(vectorB, key)) 
     cout << "Key " << key << " is in both vectors." << endl; 
    else 
     cout << "Key " << key << " is not in both vectors." << endl; 

    return 0; 
} 

UPDATE: Новый код с меньшим количеством подобного кода, который основан на идее Adapter Design Pattern:

#include <iostream> 
#include <string> 
#include <algorithm> 
#include <vector> 
#include <functional> 

using namespace std; 

class A 
{ 
    public: 
     A(int iVal) : _val(iVal) {} 
     int getVal() const { return _val; } 
    private: 
     int _val; 
}; 

class B 
{ 
    public: 
     B(int iNum) : _num(iNum) {} 
     int getNum() const { return _num; } 
    private: 
     int _num; 
}; 

// dummy number getter 
template<class T> int getNumber(const T& x) { return 0; } 

// number getter for class A 
template<> int getNumber(const A& x) { return x.getVal(); } 

// number getter for class B 
template<> int getNumber(const B& x) { return x.getNum(); } 

// comparator using the number getter 
template<class T> 
class cmp 
{ 
    private: 
     int target; 
    public: 
     cmp(int t) : target(t) {} 
     bool operator()(const T& a) const { return getNumber<T>(a) == target; } 
}; 

template<class T> 
bool isInVec(const vector<T>& vector, int iNum) 
{ 
    return find_if(vector.begin(), vector.end(), cmp<T>(iNum)) != vector.end(); 
} 

int main(void) { 
    A arrayA[] = { A(1), A(2), A(3) }; 
    vector<A> vectorA(arrayA, arrayA + sizeof(arrayA)/sizeof(A)); 

    B arrayB[] = { B(3), B(4), B(5) }; 
    vector<B> vectorB(arrayB, arrayB + sizeof(arrayB)/sizeof(B)); 

    int key = 3; 

    if(isInVec(vectorA, key) && isInVec(vectorB, key)) 
     cout << "Key " << key << " is in both vectors." << endl; 
    else 
     cout << "Key " << key << " is not in both vectors." << endl; 

    return 0; 
} 
+1

Это не устраняет дублирование кода, о котором упомянул OP, на самом деле он делает более похожий код, чтобы сделать то же самое. Более короткая версия - использовать lambdas для компараторов. – Ionut

+0

@Ionut Как насчет моего нового кода? – MikeCAT

0

Я хотел бы ответить на ваш вопрос в качестве комментария, но я не для этого достаточно репутации.

IF вектор сортируется затем с помощью «станд :: binary_search», вероятно, самый быстрый алгоритм, который вы можете использовать для поиска вектора, но помните, что вектор должен быть отсортирован.

Вы должны включить файл «алгоритм», чтобы использовать алгоритм «binary_search» (который, как я вижу, вы уже сделали).

«binary_search» может или не может работать для вас, потому что вы сказали нам предположить, что вы не можете изменить ни один из классов; если это так, вы не сможете реализовать надлежащую перегрузку оператора «меньше», если такое действие необходимо.

Проверить эту ссылку для полного описания алгоритма: http://www.cplusplus.com/reference/algorithm/binary_search/

+0

Благодарим вас за ответ. В действительности вектор не сортируется. – jiyi

+0

Да, никаких проблем. Мне лично нравится использовать бинарные поиски, когда это возможно, поскольку они во много раз быстрее, чем линейный, но необходимость сортировки данных, безусловно, является недостатком. – Fearnbuster

1

Вы противоречивый интерфейс между class A и class B. Сначала сделайте интерфейс общим, введя новый класс class C, который наследуется от class B. Затем создайте шаблонную функцию isInVec для сравнения.

class A 
{ 
    public: 
     A(int iVal) : _val(iVal) {} 
     int getVal() const { return _val; } 
    private: 
     int _val; 
}; 

class B 
{ 
    public: 
     B(int iNum) : _num(iNum) {} 
     int getNum() const { return _num; } 
    private: 
     int _num; 
}; 

class C: public B 
{ 
    public: 
     C(int iNum) : B(iNum){} 
     int getVal() const { return getNum(); } 
}; 

template <typename T> 
bool isInVec(std::vector<T> vect, int iVal) 
{ 
    for(std::vector<T>::const_iterator it=vect.begin(); it != vect.end(); it++) 
    { 
     if(it->getVal() == iVal) 
      return true; 
    } 
    return false; 
} 



int main() 
{ 
    A arrayA[] = { A(1), A(2), A(3) }; 
    std::vector<A> vecA(arrayA, arrayA + sizeof(arrayA)/sizeof(A)); 

    C arrayC[] = { C(3), C(4), C(5) }; 
    std::vector<C> vecC(arrayC, arrayC + sizeof(arrayC)/sizeof(C)); 

    int key = 3; 

    if(isInVec(vecA, key) && isInVec(vecC, key)) 
     std::cout << "Key " << key << " is in both vectors." << std::endl; 
    else 
     std::cout << "Key " << key << " is not in both vectors." << std::endl; 

    return 0; 


} 
+0

Спасибо за ваш ответ. Я боюсь, что ваш ответ не может быть скомпилирован. – jiyi

0
#include <iostream> 
#include <iterator> 
#include <algorithm> 

// class A and B unchanged, as requested 

class A 
{ 
public: 
    A(int iVal) : _val(iVal) {} 
    int getVal() const { return _val; } 
private: 
    int _val; 
}; 

class B 
{ 
public: 
    B(int iNum) : _num(iNum) {} 
    int getNum() const { return _num; } 
private: 
    int _num; 
}; 

// new predicate to cover matching 

struct matches 
{ 
    matches(int i) : _i(i) {}; 

    bool operator()(const A& a) const { 
     return a.getVal() == _i; 
    } 

    bool operator()(const B& b) const { 
     return b.getNum() == _i; 
    } 

    int _i; 
}; 

// convenience function to express the logic in a generic way 
template<class Range> 
bool contains(const Range& r, int key) 
{ 
    auto i = std::find_if(std::begin(r), 
          std::end(r), 
          matches(key)); 
    return i != std::end(r); 
} 

// test 
int main() 
{ 
    using namespace std; 

    A arrayA[] = { A(1), A(2), A(3) }; 
    B arrayB[] = { B(3), B(4), B(5) }; 

    int key = 3; 

    if (contains(arrayA, key) && contains(arrayB, key)) 
    { 
     cout << "Key " << key << " is in both vectors." << endl; 
    } 
    else { 
     cout << "Key " << key << " is not in both vectors." << endl; 
    } 

    return 0; 
} 
0

В какой-то момент вы должны различать A и B (точнее getVal и getNum). Для алгоритма поиска (как уже упоминалось) std::find_if может использоваться с предикатами, являющихся Лямбдами:

#include <algorithm> 

// ... 

int target = 5; 

auto found_A = std::find_if(vectorA.begin(), vectorA.end(), 
    [target](A const &a) -> bool { return a.getVal() == target; }); 

auto found_B = std::find_if(vectorB.begin(), vectorB.end(), 
    [target](B const &b) -> bool { return b.getNum() == target; }); 

if (found_A != vectorA.end() && found_B != vectorB.end()) 
{ 
    // target in vA and vB 
    // with found_A and found_B being valid iterators to the elements 
}