1

I don't have an interest in reinventing the wheel. I like to keep code very compact and containers are something I like to use so that I don't have to implement everything line by line. So is it possible to use those two containers together?

DaBler
  • 2,695
  • 2
  • 26
  • 46
  • Can you give an example what you want to achieve? What do you want to use as key (supposed the `forward_list` should contain the values)? – user0042 Sep 16 '17 at 09:55
  • My project has a forward_list with objects in them. Each object has a name and an id number. What I want to achieve, if possible, is to take that forward_list of objects and plug it in an unordered_map. I know how to do it line by line but I want to see if I can shorten the code. Less overhead. Basically a hash table with a singly linked list. –  Sep 16 '17 at 10:08
  • @MSquared May be [`std::transform()`](http://en.cppreference.com/w/cpp/algorithm/transform) with an appropriate lambda function. – user0042 Sep 16 '17 at 10:15
  • Ironically enough that is how far I got with my implementation. I used that line of code but I did not know how to go from there. How would I know that the objects are being sorted by index? For instance, I just added 3 items so I am going to presume I have a unordered_map of 3 indices. How do I know that the entries are spread across the map? I am concerned that maybe the objects may be all crammed into one index. –  Sep 16 '17 at 10:20
  • `std::unordered_map` doesn't have a specific sort order, neither has `std::map`. IIRC there are container classes in the `boost` library that may guarantee a `key` sorted order. – user0042 Sep 16 '17 at 10:23
  • 1
    @user0042 `std::map` keeps keys in a sorted order, as defined by comparator. – Revolver_Ocelot Sep 16 '17 at 10:25
  • @user0042 I have used transform algorithm before but not with a hash table singly linked list specifically. –  Sep 16 '17 at 10:26
  • @Revolver_Ocelot Oooops, you're correct. Might not be intuitive though. Depends on the key type. – user0042 Sep 16 '17 at 10:27
  • @user0042 I have the boost library actually so I would need to find the right header for the implementation. –  Sep 16 '17 at 10:28
  • Yeah, what @Revolver_Ocelot did I had already written. I just needed to know for sure that the unordered_map was implemented as a proper sorted hash. –  Sep 16 '17 at 10:29
  • @user0042 see my answer – sehe Sep 16 '17 at 10:40
  • @sehe Yes, that was what I had in mind. I'm not so fluent in speaking `boost` as you though ;-) – user0042 Sep 16 '17 at 10:44

1 Answers1

1

Obvsiously you can. However, consider Boost Multi-Index.

Demo

Live On Coliru

#include <unordered_map>
#include <forward_list>
#include <string>

struct Element {
    int id;
    std::string name;

    struct id_equal final : private std::equal_to<int> {
        using std::equal_to<int>::operator();
        bool operator()(Element const& a, Element const& b) const { return (*this)(a.id, b.id); };
    };
    struct name_equal final : private std::equal_to<std::string> {
        using std::equal_to<std::string>::operator();
        bool operator()(Element const& a, Element const& b) const { return (*this)(a.name, b.name); };
    };
    struct id_hash final : private std::hash<int> {
        using std::hash<int>::operator();
        size_t operator()(Element const& el) const { return (*this)(el.id); };
    };
    struct name_hash final : private std::hash<std::string> {
        using std::hash<std::string>::operator();
        size_t operator()(Element const& el) const { return (*this)(el.name); };
    };
};

int main() {

    using namespace std;
    forward_list<Element> const list { { 1, "one" }, { 2, "two" }, { 3, "three" } };

    {
        unordered_map<int, Element, Element::id_hash, Element::id_equal> map;
        for (auto& el : list)
            map.emplace(el.id, el);
    }

    {
        unordered_map<std::string, Element, Element::name_hash, Element::name_equal> map;
        for (auto& el : list)
            map.emplace(el.name, el);
    }
}

Demo With Multi-Index

This achieves the same goal but:

  • in-place (no copies of the container)
  • indexes are always in-synch
  • no manual custom hash/equality function objects

Live On Coliru

#include <string>
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

struct Element {
    int id;
    std::string name;
};

namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<Element,
      bmi::indexed_by<
            bmi::hashed_unique<bmi::tag<struct by_id>, bmi::member<Element, int, &Element::id> >,
            bmi::hashed_non_unique<bmi::tag<struct by_name>, bmi::member<Element, std::string, &Element::name> >
         >
      >;

int main() {

    using namespace std;
    Table const list { { 1, "one" }, { 2, "two" }, { 3, "three" } };

    for (auto& el : list.get<by_name>())
        std::cout << el.id << ": " << el.name << "\n";

    for (auto& el : list.get<by_id>())
        std::cout << el.id << ": " << el.name << "\n";
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Looking at the Boost implementation it doesn't look too different from the unordered_map. It looks more like a revised version of the unordered_map. It would be good see it added to Standard Library. –  Sep 16 '17 at 10:42
  • Right, the Boost one is a lot more compact. –  Sep 16 '17 at 10:44
  • I am not using a struct though. I am using a class object so I have to be forwarding private member variables. –  Sep 16 '17 at 10:45
  • @MSquared It's more like a list, but with additional indexes that appear like the map/multimap interface. It will not end up in the standard libraries because there are many ways to do it, with different tade-offs. Boost is relevant :) – sehe Sep 16 '17 at 10:45
  • [Struct vs. class](https://stackoverflow.com/questions/54585/when-should-you-use-a-class-vs-a-struct-in-c): There is no difference. For the technicalities: http://www.boost.org/doc/libs/1_65_1/libs/multi_index/doc/tutorial/key_extraction.html So, [Live Demo](http://coliru.stacked-crooked.com/a/424ccc36d9a4df85) – sehe Sep 16 '17 at 10:49
  • Yeah, but since I am big fan of shortening code I find the Boost version more attractive. Still, I am not focusing too hard on Boost because I really want to grasp a good understanding of Standard Library first. Your first implementation is very verbose to me. Can it be more compact? –  Sep 16 '17 at 10:51
  • Do you think I made it verbose on purpose. From the boost example someone how "loves shortening code" should be able to tell I'm no different. So yeah, if you cut features, it will be shorter. I've another answer that you may find inspirational. I'll find out when I get home later today – sehe Sep 16 '17 at 11:38
  • Thank you greatly. I hope it is not too much trouble if you can provide more insight just using Standard Library because I am still trying to find the solution in my project: std::forward_list acct; acct.push_front({"John",12345}); acct.push_front({"Don",54321}); acct.push_front({"Fred",67890}); std::unordered_map ht; –  Sep 16 '17 at 12:05
  • Oh, like that: [using std::reference_wrapper](http://coliru.stacked-crooked.com/a/b19014620d5039ef) or [the same thing with multi_index_container](http://coliru.stacked-crooked.com/a/b31f71a2f46db2fd). Note that now you have life-time issues, instead of copy issues. The answer MultiIndex sample doesn't have that issue – sehe Sep 16 '17 at 13:01
  • Here's the rest of it. Just so you have an idea what I am [trying to do](http://coliru.stacked-crooked.com/a/c8fa076882dc1695) –  Sep 16 '17 at 13:16
  • Now. The other source of inspiration would be boost intrusive, e.g. the [***Indexing*** section in this answer](https://stackoverflow.com/questions/45845469/make-a-boost-filtered-graph-by-vertex-label-property/45850742#45850742). Here's an application of it: http://coliru.stacked-crooked.com/a/eb86307b1238eb27 note the subtleties of intrusive containers (like using reference_wrapper, no ownership is implied, so be aware of lifetime issues and reference stability) – sehe Sep 16 '17 at 14:12
  • Ah, I see. These are Boost solutions though. Aside from the first one you did, does Standard Library have an alternative? Do I have to have a bool to make this work? –  Sep 16 '17 at 14:35
  • I suggest you reread the answer and [the comments](https://stackoverflow.com/questions/46252475/is-it-possible-to-insert-a-forward-list-into-a-unordered-map/46252892?noredirect=1#comment79471825_46252892&cough=3x). _Please_. (No, you do not have to have a ... "bool" (?)) – sehe Sep 16 '17 at 14:42