This works ok, except it adds the new value to the end of the hash map:
(swap! my-atom conj #new-fields)
I need for my-atom to be the first item in #new-fields. I have tried assoc-in, cons and pretty much everything that might "put things together". What can I do to swap! in my-atom to the front of #new-fields?
Hash-maps are unordered collections; logically they do not have a "beginning" or an "end". They have an iteration order, which is an implementation detail (based on the hashes of the keys) and which users should not rely upon. This iteration order will be consistent between readings of the same map because the map is an immutable value.
It sounds like you want a different datatype, to provide predictable ordering. Sorted maps are the easiest replacement. You can create them using sorted-map (which sorts using compare on the keys), or sorted-map-by (which takes a comparator function to compare keys with). conjing a key-value pair into one will put it first iff the new key is lowest according to the comparator.
Note that these are still logical maps: If the comparator says two keys equal one another then they are the same key and the resulting map will only have one value for them.
If you can't make that fit your requirements, it sounds like you're not actually using a logical map, since the values have both an index and a key. A few alternatives if you really need to manually set the order might be
A vector of [key value] tuples or maps with a single key/value pair.
A map with composite keys [index old-key], sorted on index, where old-key is whatever keys you're using now.
Related
When iterating over an unordered map of values, std::unordered_map<Foo, Bar>, it will use an iterator pointing to values instd::pair<Foo, Bar>. This makes it seem like std::unordered_map stores its values internally as std::pairs of values.
If I'm not mistaken, std::unordered_map works by hashing the key and using that for lookups. So, if the internal structure is something like a list of pairs, how does it know which pair has the hashed key? Wouldn't it need to hash the whole pair, value included?
If the internal structure does not hold pairs, does calling std::unordered_map::begin() then create a std::pair object using the data in the map? Then how does modifying the data in the pair also modify the data in the actual map itself?
Thank you.
Let's pretend that the map is really a single vector:
std::vector<std::pair<Foo, Bar>> container;
It's easy to visualize that iterating over this container iterates over std::pairs of two classes.
The real unordered map works the same way, except instead of a vector the map stores std::pair<Foo, Bar>s in a hash table, with additional pointers that stitch the whole hash table together, that are not exposed via the map's iterators.
The way that associative containers, like maps, get loosely explained and described -- as a key/value lookup -- makes it sound like in the maps keys and values are stored separately: here's a hash table of keys, and each key points to its corresponding value. However that is not the case. The key and its value are kept together, tightly coupled in discrete std::pair objects, and the map's internal structure arranges them in a hashed table that the iterator knows how to iterate over.
So, if the internal structure is something like a list of pairs, how does it know which pair has the hashed key?
Neither. An unordered map can be loosely described as a:
std::vector<std::list<std::pair<Key, Value>>>
A key's hash is the index in the vector. All Keys in the ith position in this vector have the same hash value. All keys with the same hash are stored in a single linked list.
I'm having a hard time wrapping my head around unordered_maps and unordered_multimaps because my test code isn't producing what I've been told to expect.
std::unordered_map<string, int> names;
names.insert(std::make_pair("Peter", 4));
names.insert(std::make_pair("George", 4));
names.insert(std::make_pair("George", 4));
When I iterate through this list, I get one instance of George first, then Peter.
1) It's my understanding unordered_maps do not allow multiple keys to map to one value, and that multimaps due. Is this true?
2) Why can Peter and George coexist at a value of 4? What is happening to the second George? And for that matter, why is George appearing first when I iterate from begin() to end() if this is unordered?
3) What is the underlying representation of an unordered map vs. unordered multimap?
4) Is there a way to insert keys into either map without providing a value? E.g. have the compiler create its own hash function that I don't need to worry about when I retrieve keys and look for collisions?
I'll make it short:
No. Multi... refers to keys. A (non-multi)map can't have multiple equivalent keys with differeny values, ie. per key there is at most one value. A multi map can. The same holds for the unordered versions.
Peter != George, which is why they have different key and may very well have the same value.
A hashmap.
Use sets.
In your example the second insertion for George using a (non-multi) is skipped as the same key was previously inserted.
You want to use unordered_multimap to have several keys that are the same.
Since this is unordered you can't really hope to have any particular order, because it depends on the hash function.
If you want order in which you insert things, you need to use std::vector. Even normal maps, which are supposed to be ordered imply the comparison order, and not the order in which you insert things, for example string "AB" comes before "BB", because "A" is less than "B".
To insert without providing a value you need a set, and not a map.
The underlying structure of "unordered_" things is hashtable.
Can you give me a brief description of Tuple? And when to use it over List and Vector?
Tuple is usually represented in Clojure through an associative data structure such as map {:name "david" :age 35} or record.
A vector ["david" 35] offers fast positional access (= 35 (nth ["david" 35] 1)), and you can store different types.
A list ("david" 35) or ("david" "justin" "david") offers fast access from the head and fast forward traversal. Although it can hold different types it would be most common for it to contain a single type, possibly containing duplicates, in a determined order. Contrast to a set #{"david" "justin"} which would contain no duplicates and is optimised for checking membership/presence.
Sorted sets (sorted-set) and maps (sorted-map) maintain the order of objects using a comparator.
Check out 4clojure and clojuredocs.org. Good luck!
When ever you will do more insertion/deletion operations in a data structure you should use a List. When ever in a data structure accessing of variables is very frequent use a vector.
Tuples are objects that pack elements of different types together in a single object, just like pair objects do for pairs of elements, but generalized for any number of elements.
Conceptually, they are similar to plain old data structures (C-like structs) but instead of having named data members, its elements are accessed by their order in the tuple.
In my application, I have a CMap of CString values. After adding the elements in the Map, if I retrieve the elements in some other place, am not getting the elements in the order of insertion.Suppose I retrieve the third element, I get the fifth like that. Is it a behavior of CMap. Why this happens?
You asked for "why", so here goes:
A Map provides for an efficient way to retrieve values by key. It does this by using a clever datastructure that is faster for this than a list or an array would be (where you have to search through the whole list before you know if an element is in there or not). There are trade-offs, such as increased memory usage, and the inability to do some other things (such as knowing in which order things were inserted).
There are two common ways to implement this
a hashmap, which puts keys into buckets by hash value.
a treemap, which arranges keys into a binary tree, according to how they are sorted
You can iterate over maps, but it will be according to how they are stored internally, either in key order (treemap) or completely unpredictable (hashmap). Your CMap seems to be a hashmap.
Either way, insertion order is not preserved. If you want that, you need an extra datastructure (such as a list).
How about read documentation to CMap?
http://msdn.microsoft.com/ru-ru/library/s897094z%28v=vs.71%29.aspx
It's unordered map really. How you retrieve elements? By GetStartPosition and GetNextAssoc? http://msdn.microsoft.com/ru-ru/library/d82fyybt%28v=vs.71%29.aspx read Remark here
Remarks
The iteration sequence is not predictable; therefore, the "first element in the map" has no special significance.
CMap is a dictionary collection class that maps unique keys to values. Once you have inserted a key-value pair (element) into the map, you can efficiently retrieve or delete the pair using the key to access it. You can also iterate over all the elements in the map.
I'm looking for a function in C++ that for swap the contents of a map ...
that is:
those that were the keys now become the items and those that the items were now the keys.
Can you tell me if there is something about this?
As Geoffroy said, std::map doesn't allow this behaviour. However, you might want to use a STL-like container Boost.Bimap - bidirectorial map.
A Bimap is a data structure that represents bidirectional relations between elements of two collections. The container is designed to work as two opposed STL maps. A bimap between a collection X and a collection Y can be viewed as a map from X to Y (this view will be called the left map view) or as a map from Y to X (known as the right map view).
There's no standard method / way to do this, you have to write your own function.
It's not something very hard to do, but first think about doing it in a different way.
If you have to invert your key/values, then you're code may be ill-though, you don't keep the logic of the container.
If you want more information, explain why you want to do this.
Insert the items in the map into a multimap - value first, key second, with appropriate comparison function that compares two values of the original map. Once all value-key items are inserted, the multimap will be sorted as intended. Job done!