std::unordered_multimap - powtarzające się ułożenie elementów.

0
#include <iostream>
#include "site_code_pl.h"
#include <map>
#include <unordered_map>
#include <chrono>
#include <random>
#include <limits>
#include <boost/functional/hash.hpp>

std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<std::size_t> dist(0, std::numeric_limits<std::size_t>::max());

static std::size_t g_seed = dist(gen);

struct dictionary {
	std::multimap<std::string, std::wstring> mmap;
	auto const get_dict() const { return mmap; }
};

template <class type>
struct cmp_key {
	bool operator() (type const& lhs, type const& rhs) const
	{
		return lhs == rhs;
	}
};

template <class type>
struct my_hash {
	std::size_t operator() (type const& val) const
	{
		std::size_t seed = g_seed; // g_seed losowany jest na początku programu i jest niezmieniany w trakcie
		boost::hash_combine(seed, val);
		return seed;
	}
};

struct unordered_dictionary {
	std::unordered_multimap<
		std::string, std::wstring, my_hash<std::string>, cmp_key<std::string>> unmmap;
	void init_unord_mmap(std::multimap<std::string, std::wstring> const& dict)
	{
		for (auto const& item : dict)
		{
			unmmap.insert(decltype(unmmap)::value_type(item.first, item.second));
		}
	}
	auto const get_unord_dict() const { return unmmap; }
};

template <class coll_t>
void print_map(coll_t const& coll)
{
	for (auto const& item : coll) {
		std::cout << item.first << " - ";
		std::wcout << item.second << L"\n";
	}
}

int main()
{
	pl();
	dictionary dict;
	dict.mmap.insert({
		{ "meadow" , L"łąka" },
		{ "fear" , L"lęk" },
		{"fear", L"strach"},
		{ "rose" , L"róża" },
		{ "knife" , L"noż" },
		{ "spoon" , L"łyżka" }
	});
	print_map(dict.get_dict());
	std::cout << "\n\n";
	unordered_dictionary unord_dict;
	unord_dict.init_unord_mmap(dict.get_dict());
	print_map(unord_dict.get_unord_dict());
} 

Niestety ten program generuje mi za każdym razem wyniki w tej samej kolejności.
Nie mogę zrozumieć jak to działa.
Gdy zamienię

std::size_t seed = g_seed;

na

std::size_t seed = dist(gen);

wtedy program generuje wyniki za każdym razem w różnej kolejności,
ale chyba jest to UB wg standardu (23.2.5.5)

edit: Przepraszam za brak pytania.
Czy mogę użyć drugiego zapisu, ew co mogę zrobić by mieć przy każdym uruchomieniu programu elementy ułożone w różnej kolejności?

1

Kompilujesz może na mingw? Ostatnio gdy sprawdzałem ich random_device zawsze zwracał tę samą sekwencję wartości :​/ . Jeśli tak to zrób sobie seed_seq i dorzuć tam randa.

Ten drugi hash to musi być UB, dla tego samego elementu zwraca różne wartości.

0

Kompilator od MS - VS2015 up.3.

Problem mam taki:
Wczytanie do multimapy haseł z tłumaczeniam (będzie używane).
Następnie chcę mieć możliwość wylosowania kilku haseł (taki test ze słówek), stąd pomysł na nieuporządkowaną multimapę. Wyświetlałbym np. 20 pierwszych losowo ułożonych.

2

No to mamy problem XY :​D To co chcesz zrobić jest osiągalne za pomocą std::sample.

Nie do końca rozumiem też problem - na wandboksie różne uruchomienia (trzeba dodać spację czy coś, żeby cache nie poszło) dają różne kolejności. Chyba, że mowa o kolejności elementów wewnątrz tego samego klucza, co jest normalne, bo mają ten sam hash (i powinny mieć!), a multimapy trzymają listy.

0

Niestety std::sample nie jest jeszcze dodane od VS2015. Zobaczę jak to się ma w VS2017.

Takie mam wyniki u siebie.

4146282455
fear - lęk
fear - strach
meadow - łąka
knife - noż
rose - róża
spoon - łyżka

1010653001
fear - lęk
fear - strach
meadow - łąka
knife - noż
rose - róża
spoon - łyżka

Jak widać g_seed generowany jest inny z każdym razem, a wyniki są takie same.

Z rana też wrzucałem kod na wandboxa i pech chciał, że trzykrotnie wyszło to samo,
więc myślałem, że zmaściłem coś z kodem. Teraz patrzyłem i wyniki różnią się.
W czym może być problem na VS?

0

Czemu mieszasz dwa problemy?
Redukuj problem do jednego tematu

  • wypisz sobie wartość g_seed by mieć pewność, że faktycznie masz tam liczbę losową o zakresie jaki się spodziewasz
  • albo ustal sobie ręcznie rożne wartości g_seed (nawet w jednym uruchomieniu kodu) i zobaczysz jak często wystąpią powtórzenia kolejności.
0

@MarekR22:

  • g_seed losowany jest prawidłowo. W poprzednim poście dodałem wypisanie tej wartości przed wypisaniem zawartości kontenera.
  • Ręcznie też wpisywałem i nic to nie zmienia.
    Kontener zachowuje się tak, jakby ignorował hasha.
    Domyślny hash też generuje zawsze to samo (poszukam jeszcze - może to jakiś bug).
1

Tak właśnie myślałem. Chodziło mi o to, że sam sobie utrudniasz analizę problemu,
Tak jest prościej: https://wandbox.org/permlink/7B1sHfM7CMZJTn6a

Teraz pytanie czemu się tak dzieje?
Tu masz ważną wskazówkę: https://wandbox.org/permlink/df48rzqrKctzputH
Jedynie co zmieniłem to minimalną liczbę kubełków na hash-e, wiec to ma związek ze sposobem organizacji i kubełków im jest ich więcej tym bardziej kolejność jest zachowana.

1 użytkowników online, w tym zalogowanych: 0, gości: 1