2012-06-21 2 views
5

Моя карта определяется как таковую: map<string, LocationStruct> myLocations; где ключ Строка временистанд :: карта - стереть последний элемент

Я только держать 40 пунктов в этой карте, и хотел бы отказаться от последнего пункта на карте, когда я достиг 40 предметов. Я знаю, что я не могу сделать myLocations.erase(myLocations.end()), так как я могу это сделать?

Я намереваюсь, чтобы последний элемент на карте был самым старым, и поэтому FIFO. Данные будут поступать довольно быстро (около 20 Гц), поэтому я надеюсь, что карта может не отставать от нее. Мне нужно искать данные, основанные на времени, поэтому мне действительно нужно, чтобы это был ключ, но я открыт для альтернативных методов достижения этого.

Формат строки - очень подробный «Четверг 21 июня 18: 44: 21: 281», хотя я могу сделать это, чтобы быть секундами с эпохи для простоты. Это был мой первый выход, и он не слишком много думал о формате.

+0

бы 'myLocations.erase (myLocations.rbegin())' не делать эту работу? – Rook

+2

Похоже, что вместо (отсортированной) карты вам нужна какая-то очередь с постоянной длиной/приоритетом. – kennytm

+0

@Rook 'map <> :: erase' принимает в качестве аргумента позиции итератор, а не reverse_iterator. –

ответ

6

Я предполагаю, что когда вы говорите «стереть последний элемент», вы имеете в виду «стереть старейший элемент».

Я бы не использовал строку для раз, вместо этого используйте тип даты/времени (например, временную метку unix). Затем они будут сортироваться по времени, а не лексикографически, и вы можете myLocations.erase(myLocations.begin()), так как старейший всегда будет в начале.

Еще лучше, используйте boost::circular_buffer<std::pair<timetype, LocationStruct>> и используйте std::lower_bound, чтобы найти элементы по времени. Это автоматически удалит самую старую для вас и будет иметь такую ​​же логарифмическую сложность при поиске элемента по времени. Это также быстрее при добавлении данных. Это в значительной степени выигрывает вокруг вашей ситуации. Если вы действительно хотите избежать boost, то std::deque соответствует вашим потребностям лучше всего и дает отличную производительность, но если у вас уже есть рабочий map, то пребывание с std::map, вероятно, лучше всего.

Вот как сделать находку в deque:

typedef ???? timetype; 
typedef std::pair<Timetype, LocationStruct> TimeLocPair 
typedef std::deque<TimeLocPair> LocationContainer; 
typedef LocationContainer::const_iterator LocationIterator; 

bool compareTimeLocPair(const TimeLocPair& lhs, const TimeLocPair& rhs) 
{return lhs.first < rhs.first;} 

LocationIterator find(const LocationContainer& cont, timetype time) { 
    TimeLocPair finder(time, LocationStruct()); 
    LocationIterator it = std::lower_bound(cont.begin(), cont.end(), finder, compareTimeLocPair); 
    if (it == cont.end() || it->first != time) 
     return cont.end(); 
    return it; 
} 
+0

Это зависит от того, как строка хранится на дату. Он должен был заботиться о дате, если сказал, что время не принадлежит к тому же дню, о котором я упомянул в своем ответе. – Invictus

+0

@Ritesh: Это то, что я намеревался, но согласно вашему путаница, я уточнил слова и предоставил образец. –

+0

Мне нужно будет выяснить, как именно я получу время, чтобы найти ключ. Это приведет к моему ключевому формату. – Jason

0

Поскольку вы Запоминание время как ключевой строки. Последний элемент (ранний по времени в день времени, учитывая с 00:00 до 24:00) будет нижней границей элемента и, следовательно, Вы можете получить итератор, как этот

 `map<string, LocationStruct>::iterator it;` 
     it=myLocations.lower_bound ('00:00'); 
     myLocations.erase (it, it+1); 

Но if it belongs to different dates, то вам нужно еще рассмотрите день и соответствующим образом создайте свой код. Как вы упомянули data is coming quick enough, вам не нужно учитывать дату. Но The safe way here would be take the entire date in terms of second and remove the lowest one as mentioned above. Это позаботится, даже если частота поступления новых данных будет довольно медленной.

+0

Он уточнил синтаксис строки, ответ нуждается в обновлении. –

+0

@MooingDuck Done – Invictus

+0

все еще не обрабатывает 23:59, за которым следует 00:01 –

1

Ну, быстрая проверка на г ++ 4.4 предполагает, что это работает просто отлично:

myLocations.erase(myLocations.rbegin()->first); 

хотя я должен признаться, что я не знаю, почему он не любит принимать только сам итератор.

+0

Это передает ключ последнего элемента, а ключ - это действительная вещь, чтобы перейти к 'erase'. Это медленное, хотя, по сравнению с простым передачей итератора последнему элементу. –

+1

Потому что 'rbegin' возвращает итератор _reverse_ –

+1

Да, я знаю об этом. Поэтому почему я на самом деле сказал: «Я не знаю, почему он не любит принимать только сам итератор». – Rook

11

Самого идиоматических способ будет:

myLocations.erase(std::prev(myLocations.end())); 

Если вы не га в C++ 11, используйте соответствующую функцию из вашего инструментов.

+0

Это предполагает, что строки сортируются хонологически, а не лексикографически –

+1

@MooingDuck Вот что он просил: как удалить последний элемент. –

+0

Вопрос был обновлен, чтобы уточнить: «Я намереваюсь, чтобы последний элемент на карте был самым старым, а значит, и FIFO». «Формат строки очень подробный» Четверг 21 июня 18: 44: 21: 281 «...», учитывая эту информацию, этот ответ неверен. –

4

Попробуйте, это работает:

map<string, LocationStruct>::iterator it = myLocations.end(); 
it--; 
myLocations.erase(it); 
+0

, если 'myLocations' не имеет нулевого размера, но это, вероятно, предположение, что это дано – IceFire