-2

std::distance seems to be very slow. I have a large multimap and try to use equal_range to find the element with common key:

auto range = in_map.equal_range(neuron_with_spikes[i]); 
int count = std::distance(range.first, range.second); 

The std::distance takes more time than equal_range. Naively I would assume when doing equal_range, the distance is automatically calculated. In fact, it's two independent calculations.

Is there a different way to get the total number of element of the equal_range?

David
  • 325
  • 2
  • 12
  • Do you need both the range and the count? – NathanOliver Jul 29 '19 at 16:53
  • 4
    What are the inherent complexities (think "Big-O Notation") of your operations on your container? Maybe, `multimap` is just not the right tool? – Ulrich Eckhardt Jul 29 '19 at 16:54
  • 2
    There's [`std::multimap::count`](https://en.cppreference.com/w/cpp/container/multimap/count), but it has the same complexity as what you wrote here. – Justin Jul 29 '19 at 16:57
  • I need to count to save the time from a vector::push_back in the loop following it. – David Jul 29 '19 at 17:52
  • So all you are trying to do is reserve the right size? In the pushing back it is going to visit every node in the range anyway, so I think you just can't win this one, unless you could guestimate the vector reserve size as 1/2 the map's size()? – Gem Taylor Jul 29 '19 at 18:48
  • My multimap is sorted, i.e. all of the same key value are right next to each other. Can one just get the first index and the last index number of the range to speed it up? – David Jul 29 '19 at 18:57
  • What do you mean by "*the element with common key*", the first such element, or any such element? Or am I misunderstanding the question entirely? Anyway, can you please provide a [mcve]? – rustyx Jul 29 '19 at 19:15
  • I mean "value with common key" since this is a multimap and there can be multiple values associated with the same key. In my case, the key is sorted. That means, the same keys are grouped together. – David Jul 31 '19 at 14:36

2 Answers2

2

std::multimap::equal_range is O(log <size of the container>) and std::distance is O(linear <size of the range>) and std::multimap::count is the sum of those two.

This is total reasonable as the map is sorted and you need to visit each element in the range to count them - so unless you can get rid of some this in your solution - looks like normal behavior for what you're trying to do.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
1

No; it is possible to implement a std map type construct where counting the distance between iterators is O(lg n), but std maps do not implement it. And retrofitting it is not easy; writing your own container is probably just as easy.

In such a modified map, the balanced binary tree keeps track of total nodes under; this adds a constant overhead factor to tree mutation and memory usage, but none in O notation.


The easiest way, because you only need count and not distance, probably to replace your multimap with a map from key to vector of elements; and manually manage the vector of elements. Distance is O(n) but count becomes O(lg n).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • My multimap is sorted, i.e. all of the same key value are right next to each other. Can one just get the first index and the last index number of the range to speed it up? – David Jul 29 '19 at 19:02
  • 2
    @David There is no way to go from iterator to index number in a std map or multimap short of O(n) time. Hence, the very first word in my answer. The second paragraph sketches a std map/multimap like container that has the property to get index in log n time; it is not what std map or multimap does. I know you cannot do it using std map containers, because I've wanted it and tried repeatedly. The third paragraph details a workaround, replacing multimap with a std map to a vector (or even a std map to a std set or almost anything that has O(1) count). – Yakk - Adam Nevraumont Jul 29 '19 at 20:11
  • the 3rd option sounds the more straight way to go. Thanks – David Jul 31 '19 at 14:40