将多重贴图转换为一组集合

发布于 2024-09-30 23:52:57 字数 77 浏览 7 评论 0原文

我有一个多重映射,我想获得一组集合 - 它将多重映射中共享相同密钥的所有类型 A 的项目分组在一起。 STL中有内置的方法可以做到这一点吗?

I have a multimap and I would like to get a set of sets - which would group together all the items of type A in the multimap that share the same key. Is there a built-in way to do this in STL?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

帅气称霸 2024-10-07 23:52:57

我不认为有内置的方法。然而,手动操作很容易:

std::multimap<key, value> mm;
// ...
std::multimap<key, value>::const_iterator i = mm.begin();
while (i != mm.end())
{
    std::multimap<key, value>::const_iterator end = mm.upper_bound(i->first);
    // construct a set from the values in [i, end)
    i = end;
}

或者类似的事情。

I don't think there is a built-in way. However it is easy to do manually:

std::multimap<key, value> mm;
// ...
std::multimap<key, value>::const_iterator i = mm.begin();
while (i != mm.end())
{
    std::multimap<key, value>::const_iterator end = mm.upper_bound(i->first);
    // construct a set from the values in [i, end)
    i = end;
}

Or something like that.

你是我的挚爱i 2024-10-07 23:52:57

您可以在一对上使用一组。

首先定义该对。该对需要密钥作为第一个元素,您的实例作为第二个元素。

例如,假设我们有一个书籍集合,我们想按作者对它们进行分组:

typedef std::pair<Author *,Book *> AuthorBookPair;

然后您在此对上定义一个集合:

typedef set<AuthorBookPair> BooksGroupedByAuthor;

可以像这样填充该集合:

BooksGroupedByAuthor books;
books.insert (std::make_pair(book1->getAuthor(),book1));
books.insert (std::make_pair(book2->getAuthor(),book2));
books.insert (std::make_pair(book3->getAuthor(),book3));
books.insert (std::make_pair(book4->getAuthor(),book4));

现在您可以使用 lower_bound 和 upper_bound 简单地查找作者的书籍方法:

#define POINTER_SMALLEST 0x00000000
#define POINTER_LARGEST  0xffffffff

BooksGroupedByAuthor::const_iterator lowerbound = books.lower_bound(std::make_pair(myFavoriteAuthor,POINTER_POINTER));
BooksGroupedByAuthor::const_iterator upperbound = books.upper_bound(std::make_pair(myFavoriteAuthor,POINTER_POINTER));

现在只需在下限和上限之间进行迭代即可获取该作者的所有书籍。

这个技巧依赖于这样一个事实:我选择存储指向书籍的指针,并且我知道最小和最大的指针是什么(对于 64 位应用程序,您必须更改它!)。我必须承认这不是最好的把戏。

一个稍微好一点的替代方案是存储书籍本身(如果您的应用程序允许创建这些实例的副本)并创建 2 个特定的 Book 实例,分别代表“最小的书”和“最大的书”。

这个技巧的好处是它允许在需要时添加更多维度。例如,您可以添加年份作为第二个维度,然后选择仅查找某个作者的书籍,或者查找特定年份某个作者的书籍。当使用更多维度时,新 C++0x 中的元组可能会变得很方便。

这个技巧还有一个优点,它可以防止你两次添加一本书。如果一本书被添加两次,它仍然会在集合中出现一次(如果我们假设这本书的作者永远不会改变)。如果您使用 multi_map,则可以将同一本书添加两次,这可能是不需要的。

You could use a set on a pair.

First you define the pair. The pair needs the key as first element and your instance as second element.

E.g. suppose we have a collection of books and we want to group them by author:

typedef std::pair<Author *,Book *> AuthorBookPair;

Then you define a set on this pair:

typedef set<AuthorBookPair> BooksGroupedByAuthor;

Filling the set can be done like this:

BooksGroupedByAuthor books;
books.insert (std::make_pair(book1->getAuthor(),book1));
books.insert (std::make_pair(book2->getAuthor(),book2));
books.insert (std::make_pair(book3->getAuthor(),book3));
books.insert (std::make_pair(book4->getAuthor(),book4));

You can now simply look up books of an author using the lower_bound and upper_bound methods:

#define POINTER_SMALLEST 0x00000000
#define POINTER_LARGEST  0xffffffff

BooksGroupedByAuthor::const_iterator lowerbound = books.lower_bound(std::make_pair(myFavoriteAuthor,POINTER_POINTER));
BooksGroupedByAuthor::const_iterator upperbound = books.upper_bound(std::make_pair(myFavoriteAuthor,POINTER_POINTER));

Now simply iterate between lowerbound and upperbound to get all the books from this author.

This trick relies on the fact that I chose to store pointers to books, and that I know what the smallest and the largest pointer is (for 64-bit apps you will have to change this !). I must admit this is not the nicest trick.

A slightly better alternative would be to store the books themselves (if it is allowed in your application to make copies of these instances) and make 2 specific instances of Book that represent the 'smallest book' and the 'largest book' respectively.

The nice thing about this trick is that it allows adding more dimensions if needed. E.g. you could add the year as a second dimension, and then choose to look up books from an author only, or looking up books from an author in a specific year. When using more dimensions, the tuples from the new C++0x may become handy.

This trick also has the advantage that it protects you from adding a book twice. If a book is added twice, it will still be once in the collection (if we assume that the author of the book never changes). If you would use a multi_map, you could add the same book twice, which is probably not wanted.

远山浅 2024-10-07 23:52:57

您可以按照以下方式执行某些操作(但使用更合适的名称)。请注意,输出结构实际上是集合的映射而不是集合的集合,因为这样您就保留了键。

#include <map>
#include <set>


template <class key_t, class value_t>
struct transform_fn {
    typedef std::multimap<key_t, value_t> src_t;
    typedef std::map<key_t, std::set<value_t> > dest_t;

    dest_t operator()(src_t const& src) const
    {
        dest_t dest;
        typedef typename src_t::const_iterator iter_t;
        for (iter_t i = src.begin(), e = src.end(); i != e; ++i) {
            dest[i->first].insert(i->second);
        }
        return dest;
    }
};

#include <string>

int
main()
{
    typedef std::multimap<std::string, int> some_map_t;
    typedef std::map<std::string, std::set<int> > tr_some_map_t;

    some_map_t src;
    transform_fn<std::string, int> tr;
    tr_some_map_t dest = tr(src);

    return 0;
}

You could do something along the lines of (but with more appropriate names) the following. Note that the output structure is actually a map of sets rather than a set of set because that way you retain the keys.

#include <map>
#include <set>


template <class key_t, class value_t>
struct transform_fn {
    typedef std::multimap<key_t, value_t> src_t;
    typedef std::map<key_t, std::set<value_t> > dest_t;

    dest_t operator()(src_t const& src) const
    {
        dest_t dest;
        typedef typename src_t::const_iterator iter_t;
        for (iter_t i = src.begin(), e = src.end(); i != e; ++i) {
            dest[i->first].insert(i->second);
        }
        return dest;
    }
};

#include <string>

int
main()
{
    typedef std::multimap<std::string, int> some_map_t;
    typedef std::map<std::string, std::set<int> > tr_some_map_t;

    some_map_t src;
    transform_fn<std::string, int> tr;
    tr_some_map_t dest = tr(src);

    return 0;
}
扛刀软妹 2024-10-07 23:52:57

这将创建一个集合映射。套套其实没有任何意义。

对于集合中的每个元素,您可以执行以下操作:

our_map[iter->first].insert(iter->second);

如果您有迭代器或

our_map[p.first].insert(p.second);

带有 value_type 对。

无论哪种方式,如果未找到 iter->first,outer_set 上的operator[]将创建一个空的内部集,如果键已经存在,则将检索现有的内部集。

这会起作用,但不是最有效的方法。原因是我们知道 p.first 要么匹配我们看到的最后一个键,要么我们必须在末尾插入,但上面每次都进行查找。因此,更有效的方法是保留我们的集合迭代器。这里的 value_type 是我们的 multimap 的值类型,

BOOST_FOREACH( elt, our_multimap )
{
    if( our_map.empty() || elt.key != last_key )
    {
       last_key = elt.key;
       map_iter = our_map.insert( 
          std::make_pair<elt.key, std::set<value_type>(), 
          our_map.end() ).first;
    }
    our_iter->insert( elt.value );
}

请注意,我们在插入时捕获迭代器,它是 std::map 返回的对中的第一个。

如果您不想使用迭代器,可以使用指向 std::set 的指针,如下所示。

std::set<value_type> *p_set = NULL;
key_type last_key;
BOOST_FOREACH( elt, our_multimap )
{
    if( !p_set || elt.key != last_key )
    {
       last_key = elt.key;
       p_set = &our_map[elt.key];
    }
    p_set->insert( elt.value );
}

这仍然具有当我们按下重复键时不必查找的优点,但缺点是我们无法像插入一样将“提示”传递给operator[]。

This creates a map of sets. Set of sets doesn't really make sense.

for each element in your set you can do:

our_map[iter->first].insert(iter->second);

if you have iterators or

our_map[p.first].insert(p.second);

with value_type pairs.

Either way, operator[] on outer_set will create an empty inner set if iter->first is not found and will retrieve the existing one if the key already exists.

This will work but will not be the most efficient way to do it. The reason is that we know that p.first either matches the last key we saw or we must insert at the end, but the above is doing a lookup every time. Thus a more efficient way is to hold on to our set iterator. value_type here is the value type of our multimap

BOOST_FOREACH( elt, our_multimap )
{
    if( our_map.empty() || elt.key != last_key )
    {
       last_key = elt.key;
       map_iter = our_map.insert( 
          std::make_pair<elt.key, std::set<value_type>(), 
          our_map.end() ).first;
    }
    our_iter->insert( elt.value );
}

Note we are capturing the iterator as we insert, it is the first of the pair returned by std::map.

If you don't want to work with iterators you can use a pointer to a std::set like this.

std::set<value_type> *p_set = NULL;
key_type last_key;
BOOST_FOREACH( elt, our_multimap )
{
    if( !p_set || elt.key != last_key )
    {
       last_key = elt.key;
       p_set = &our_map[elt.key];
    }
    p_set->insert( elt.value );
}

This still has the advantage of not having to look up when we hit a duplicate key, but has the disadvantage that we can't pass a "hint" to operator[] like we could to insert.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文