具有OR搜索功能的多键容器

Multi-key container with OR search capabilities

本文关键字:OR 搜索 功能 具有      更新时间:2023-10-16

我正在寻找一个可以容纳多个键的容器,如果我为其中一个键值输入保留值(例如0),则将其视为"或"搜索。

map< pair<int, int>, int > myContainer;
myContainer.insert(make_pair(1, 1), 650);
myContainer.insert(make_pair(2, 4), 827);
myContainer.insert(make_pair(3, 1), 5);
myContainer.insert(make_pair(3, 2), 943254);
pair<int, int> key1 = make_pair(1, 1);
pair<int, int> key2 = make_pair(3, 0);
pair<int, int> key3 = make_pair(0, 1);
pair<int, int> key4 = make_pair(0, 0);
auto it = myContainer.find(key1);
cout << it->second << endl;      // it->second is an array or vector or values
it = myContainer.find(key2);
cout << it->second << endl;      // I know this isn't how to output all values in a vector
it = myContainer.find(key3);
cout << it->second << endl;      // But this demonstrates the sort of thing I'm after
it = myContainer.find(key4);
cout << it->second << endl;
所需输出:

650
5, 943254
650, 5
650, 827, 5, 943254

我正在处理与多种算法相互关联的各种数据。然而,每种算法所拥有的信息不足以完全正确地定义所有密钥来收集每个单独的信息包。在稍后的阶段,所有的信息将被传递到一个更中央的数据库(可能使用SQLite或其他东西,在这个阶段不知道)。

我对c++还是个新手,目前对数据库一无所知。另一方面,我确实有一些时间来学习东西。抱歉,如果这是一个模糊的问题,但有可能不得不学习至少一种新的语言在卡片上,我想我不妨问一些方向!提前感谢所有的帮助。

目前使用:Qt与c++在Windows 7或Ubuntu 12.04

Brandon的回答:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/range/any_range.hpp>
#include <iostream>
using namespace boost::multi_index;
struct element{int k1,k2,data;};
typedef multi_index_container<
  element,
  indexed_by<
    ordered_unique<
      composite_key<
        element,
        member<element,int,&element::k1>,
        member<element,int,&element::k2>
      >
    >,
    ordered_non_unique<member<element,int,&element::k2>>
  >
> multi_t;
typedef boost::any_range<
  element,
  boost::bidirectional_traversal_tag,
  const element&,
  std::ptrdiff_t
> range_t;
inline range_t range(const multi_t& m,const std::pair<int,int>& k)
{
  if(k.second==0){
    if(k.first==0){
      return range_t(m.begin(),m.end());
    }
    else{
      auto p=m.equal_range(k.first);
      return range_t(p.first,p.second);
    }
  }
  else if(k.first==0){
    auto p=m.get<1>().equal_range(k.second);
    return range_t(p.first,p.second);
  }
  else{
    auto p=m.equal_range(boost::make_tuple(k.first,k.second));
    return range_t(p.first,p.second);
  }
}
inline std::ostream& operator<<(std::ostream& os,const range_t& r)
{
  for(const auto& e:r){
    os<<e.data<<",";
  }
  return os;
}
int main()
{
  multi_t m={{1,1,650},{2,4,827},{3,1,5},{3,2,943254}};
  std::cout<<range(m,{1,1})<<"n";
  std::cout<<range(m,{3,0})<<"n";
  std::cout<<range(m,{0,1})<<"n";
  std::cout<<range(m,{0,0})<<"n";
}

这是一个版本,工作(好…它涵盖了您的输入),它使用boost::multi-index:

#include <set>
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
using namespace boost::multi_index;
template <typename T, typename KeyElementType = int>
class or_container
{
    typedef KeyElementType key_element_type;
    struct default_index{};
    struct keyx_index{};
    struct keyy_index{};
    struct datum
    {
        datum(const std::pair<key_element_type, key_element_type>& key, T value)
            : key_x(key.first)
            , key_y(key.second)
            , value(value)
        {
            assert(0 != key_x);
            assert(0 != key_y);
        }
        datum(key_element_type key_x, key_element_type key_y, T value)
            : key_x(key_x)
            , key_y(key_y)
            , value(value)
        {
            assert(0 != key_x);
            assert(0 != key_y);
        }
        std::pair<key_element_type, key_element_type> get_key() const
        {
            return std::make_pair(key_x, key_y);
        }
        operator const T& () const
        {
            return value;
        }
        operator T& ()
        {
            return value;
        }
        key_element_type key_x;
        key_element_type key_y;
        T value;
    };
    typedef multi_index_container
        <
            datum
          , indexed_by
            <
                ordered_non_unique<tag<default_index>, const_mem_fun<datum, std::pair<key_element_type, key_element_type>, &datum::get_key> >
              , ordered_non_unique<tag<keyx_index>, member<datum, key_element_type, &datum::key_x> >
              , ordered_non_unique<tag<keyy_index>, member<datum, key_element_type, &datum::key_y> >
            >
        > container;
    container m_cont;
public:
    typedef std::pair<key_element_type, key_element_type> key_type;
    or_container()
    {}
    //! precondition: key indices do not contain 0 values.
    //! @return whether the value was inserted for the specified key.
    bool insert(key_type key, const T& value)
    {
        assert(key.first != 0 && key.second != 0);            
        if (!key.first || !key.second)
            return false;
        return m_cont.insert(datum(key, value)).second;
    }
    std::size_t size() const { return m_cont.size(); }
    std::set< std::reference_wrapper<const T> > find(key_type key) const
    {
        std::set< std::reference_wrapper<const T> > values;
        if (key.first != 0 && key.second != 0)
        {
            const auto& index = m_cont.get<default_index>();
            std::transform(index.lower_bound(key), index.upper_bound(key), std::inserter(values, values.end()), [](const datum& d){ return std::reference_wrapper<const T>(d); });
        }
        else if (key.first == 0 && key.second == 0)
        {
            std::transform(m_cont.begin(), m_cont.end(), std::inserter(values, values.end()), [](const datum& d){ return std::reference_wrapper<const T>(d); });
        }
        else
        {
            if (key.first == 0)
            {
                const auto& index = m_cont.get<keyy_index>();
                std::transform(index.lower_bound(key.second), index.upper_bound(key.second), std::inserter(values, values.end()), [](const datum& d){ return std::reference_wrapper<const T>(d); });
            }
            if (key.second == 0)
            {
                const auto& index = m_cont.get<keyx_index>();
                std::transform(index.lower_bound(key.first), index.upper_bound(key.first), std::inserter(values, values.end()), [](const datum& d){ return std::reference_wrapper<const T>(d); });
            }
        }
        return values;
    }
};
template <typename T, typename Cmp, typename Alloc>
std::ostream& operator << (std::ostream& os, const std::set<T, Cmp, Alloc>& s)
{
    os << "{ ";
    int i = 0;
    for (T value : s)
    {
        if (i++)
            os << ", ";
        os << value;
    };
    os << " }";
    return os;
}
int main()
{ 
    using namespace std;
    or_container<int> myContainer;
    myContainer.insert(make_pair(1, 1), 650);
    myContainer.insert(make_pair(2, 4), 827);
    myContainer.insert(make_pair(3, 1), 5);
    myContainer.insert(make_pair(3, 2), 943254);
    pair<int, int> key1 = make_pair(1, 1);
    pair<int, int> key2 = make_pair(3, 0);
    pair<int, int> key3 = make_pair(0, 1);
    pair<int, int> key4 = make_pair(0, 0);
    auto s = myContainer.find(key1);
    cout << s << endl;      // it->second is an array or vector or values
    s = myContainer.find(key2);
    cout << s << endl;      // I know this isn't how to output all values in a vector
    s = myContainer.find(key3);
    cout << s << endl;      // But this demonstrates the sort of thing I'm after
    s = myContainer.find(key4);
    cout << s << endl;
    return 0;
}
输出:

{650}

{5,943254}

{5,650}

{5,650, 827,943254}

严格来说,boost::multi_index是不必要的。这可能更有效率。

这是一个使用stl(我认为还有c++ 03)的版本,并进行了Joaquín提出的一些优化:

#include <map>
#include <set>
#include <algorithm>
#include <iterator>
#include <cassert>
#include <iostream>
template <typename T, typename KeyElementType = int>
class or_container
{
    typedef KeyElementType key_element_type;
    struct datum
    {
        datum(const std::pair<key_element_type, key_element_type>& key, T value)
            : key(key)
            , value(value)
        {
            assert(0 != key.first);
            assert(0 != key.second);
        }
        operator const T& () const
        {
            return value;
        }
        bool operator <(const datum& rhs) const
        {
            return key < rhs.key;
        }
        bool operator <(const key_element_type& rhs) const
        {
            return key.first < rhs;
        }
        friend bool operator <(const key_element_type& lhs, const datum& rhs)
        {
            return lhs < rhs.key.first;
        }
        bool operator <(const std::pair<key_element_type, key_element_type>& rhs) const
        {
            return key < rhs;
        }
        friend bool operator <(const std::pair<key_element_type, key_element_type>& lhs, const datum& rhs)
        {
            return lhs < rhs.key;
        }
        std::pair<key_element_type, key_element_type> key;
        T value;
    };
    typedef std::multiset<datum> data_set;
    typedef typename data_set::iterator datum_iterator;
    data_set m_cont;
    typedef std::multimap<key_element_type, datum_iterator> y_index;
    y_index m_yindex;
public:
    typedef std::pair<key_element_type, key_element_type> key_type;
    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    or_container()
    {}
    //! precondition: key indices do not contain 0 values.
    //! @return whether the value was inserted for the specified key.
    bool insert(key_type key, const T& value)
    {
        assert(key.first != 0 && key.second != 0);
        if (!key.first || !key.second)
            return false;
        datum_iterator it = m_cont.insert(datum(key, value));
        m_yindex.insert(std::make_pair(key.second, it)); 
        return true;
    }
    std::size_t size() const { return m_cont.size(); }
    std::multiset<T> find(const key_type& key) const
    {
        struct deref_map_iter_value
        {
            const_reference operator()(const typename y_index::value_type& item) { return *item.second; }
        };
        std::multiset<T> values;
        if (key.second == 0)
            if (key.first == 0)
                std::copy(m_cont.begin(), m_cont.end(), std::inserter(values, values.end()));
            else
                std::copy(std::lower_bound(m_cont.begin(), m_cont.end(), key.first), std::upper_bound(m_cont.begin(), m_cont.end(), key.first), std::inserter(values, values.end()));
        else if (key.first == 0)
            std::transform(m_yindex.lower_bound(key.second), m_yindex.upper_bound(key.second), std::inserter(values, values.end()), deref_map_iter_value());
        else
            std::copy(std::lower_bound(m_cont.begin(), m_cont.end(), key), std::upper_bound(m_cont.begin(), m_cont.end(), key), std::inserter(values, values.end()));
        return values;
    }
};
template <typename T, typename Cmp, typename Alloc>
std::ostream& operator << (std::ostream& os, const std::multiset<T, Cmp, Alloc>& s)
{
    os << "{ ";
    int i = 0;
    for (T value : s)
    {
        if (i++)
            os << ", ";
        os << value;
    };
    os << " }";
    return os;
}
int main()
{
    using namespace std;
    or_container<int> myContainer;
    myContainer.insert(make_pair(1, 1), 650);
    myContainer.insert(make_pair(2, 4), 827);
    myContainer.insert(make_pair(3, 1), 5);
    myContainer.insert(make_pair(3, 2), 943254);
    pair<int, int> key1 = make_pair(1, 1);
    pair<int, int> key2 = make_pair(3, 0);
    pair<int, int> key3 = make_pair(0, 1);
    pair<int, int> key4 = make_pair(0, 0);
    std::multiset<int> s = myContainer.find(key1);
    cout << s << endl;      // it->second is an array or vector or values
    s = myContainer.find(key2);
    cout << s << endl;      // I know this isn't how to output all values in a vector
    s = myContainer.find(key3);
    cout << s << endl;      // But this demonstrates the sort of thing I'm after
    s = myContainer.find(key4);
    cout << s << endl;
    return 0;
}