具有OR搜索功能的多密钥容器

时间:2014-07-31 17:22:42

标签: c++ qt containers

我正在寻找一个可容纳多个密钥的容器,如果我为其中一个密钥值输入保留值(例如0),则将其视为“OR”搜索。

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 ++的大部分内容仍然相对较新,目前对数据库一无所知。另一方面,我有一些时间在我的手上学习东西。对不起,如果这是一个模糊的问题,但有可能必须在卡上学习至少1种新语言,我想我也可以问一些方向!提前感谢您提供的任何帮助。

目前使用:Qt with Windows 7或Ubuntu 12.04

3 个答案:

答案 0 :(得分:3)

布兰登回答的一个变种:

#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";
}

答案 1 :(得分:0)

这是一个使用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是不必要的。它可能更有效率。

答案 2 :(得分:0)

这是一个版本,只使用了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;
}