Скопируйте std :: map в std :: vector пар

Я пытаюсь скопировать карту в вектор пары, чтобы затем отсортировать вектор по члену данных пары second. Я решил это следующим образом:

void mappedWordsListSorter(){
  for (auto itr = mappedWordsList.begin(); itr != mappedWordsList.end(); ++itr){
    vectorWordsList.push_back(*itr);
  }
  sort(vectorWordsList.begin(), vectorWordsList.end(), [=](pair<string, int>& a, pair<string, int>& b){return a.second > b.second;});
}

Мне нужно найти способ сделать это без использования необработанного цикла, используя вместо этого стандартную библиотеку. Я встречал множество примеров, когда переносили только ключи или значения карты. Мне нужно скопировать в вектор pairs<string, int>. Как лучше всего это сделать?

@Lorand - сортировка происходит по элементу second в паре, который не является ключевым.

StoryTeller - Unslander Monica 19.12.2018 16:37

@Lorand Кажется, что OP хочет выполнить сортировку на основе значений, а не ключей.

ネロク 19.12.2018 16:38

Думаю, точный дубликат. stackoverflow.com/questions/684475

Drew Dormann 19.12.2018 16:39

Похоже, этот вопрос следует пометить как дубликат этого, поскольку ответ, предоставленный @NathanOliver, намного лучше, чем любой из ответов на этот вопрос. Обновлено: хотя этот вопрос включает в себя сортировку результата.

François Andrieux 19.12.2018 16:40

@ FrançoisAndrieux Я согласен, эти ответы намного качественнее. Есть ли прецедент пометки старого вопроса как дубликата нового? Редактировать: Там есть. Я пометил старый вопрос как повторяющийся. Ответы казались более низкого качества.

Drew Dormann 19.12.2018 16:41

Примечание: когда вы передаете лямбда-запись [] вместо [=] - то, как вы ее используете, технически вызывает огромную ошибку производительности, поскольку передает все доступные переменные копированием (при компиляции Release это должно исключить ненужное копирование, но это может разрушить среду выполнения отладки. ).

ALX23z 19.12.2018 16:43

@DrewDormann: Я не думаю, что есть что-то о пометке дубликатов, что говорит о том, что новые вопросы должны указывать на старые. Но я недостаточно уверен в политике сайта, чтобы делать это сам, возможно, я что-то упустил.

François Andrieux 19.12.2018 16:46

@ ALX23z - Я согласен, что [=] не должно быть. Но то, что он там, не означает, что все копируется. Лямбда должна использовать что-то из окружающей области, чтобы захватить это.

StoryTeller - Unslander Monica 19.12.2018 16:46

@ ALX23z На самом деле, он будет копировать переменную только в том случае, если вы используете ее в теле лямбда. Использование [=] не снижает производительности, если вы не используете какие-либо переменные в области видимости.

NathanOliver 19.12.2018 16:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
20
9
2 135
3

Ответы 3

Вы можете использовать std::copy и std::back_inserter:

std::copy(mappedWordsList.begin(), 
          mappedWordsList.end(), 
          std::back_inserter(vectorWordsList));

Честно говоря, мне кажется, что петля range-for понятнее:

for(const auto& kv : mappedWordsList) 
     vectorWordsList.emplace_back(kv);

Тем не менее, вы можете использовать std::vector::reserve для предварительного выделения памяти на вашем целевом vector, избегая ненужных перераспределений.

Просто используйте функцию-член std::vectorassign.

//no need to call reserve, bidirectional iterators or better will compute the size and reserve internally.
vectorWordsList.assign(mappedWordsList.begin(), mappedWordsList.end());

Если у вас есть существующие значения в векторе, которые вы не хотите перезаписывать, используйте вместо этого insert, например

vectorWordsList.reserve(vectorWordsList.size() + mappedWordsList.size()); // make sure we only have a single memory allocation
vectorWordsList.insert(vectorWordsList.end(), mappedWordsList.begin(), mappedWordsList.end());

Я хотел бы надеяться, что assign по сути будет reserve внутренне.

François Andrieux 19.12.2018 16:41

@ FrançoisAndrieux Скорее всего, это произойдет, если вы передадите итераторы с произвольным доступом, но поскольку map имеет двунаправленные итераторы, требуется обход, чтобы узнать, сколько элементов выделять пространство, поэтому он не собирается этого делать.

NathanOliver 19.12.2018 16:43

@NathanOliver libstdC++ фактически делает reserve внутренне. Для любого ForwardIterator он вызовет std::distance, заплатив за обход чего-либо, кроме RandomAccessIterator. Вы можете отследить std::vector::assign до здесь.

Justin 19.12.2018 20:43

@ Джастин Круто. Спасибо, что нашли это. Я по-прежнему предпочитаю быть явным, если другие реализации этого не делают.

NathanOliver 19.12.2018 20:47

Размещение .resize(0) перед .reserve() может быть оптимизацией, если элементы должны быть заменены.

Deduplicator 19.12.2018 21:46

Поскольку assign не требует MoveInsertable, если итератор является прямым или более сильным, он должен зарезервировать и не должен перераспределяться при задании таких итераторов. Кроме того, во втором случае reserve является антипаттерном (предотвращает экспоненциальный рост и может привести к квадратичному поведению).

T.C. 20.12.2018 12:58
reserve по-прежнему не рекомендуется во втором случае, если вы не знаете, что не расширяете вектор дальше. Если я запустил второй фрагмент кода в цикле, он перераспределил бы каждая итерация, тогда как если бы я просто использовал insert без reserve, сработало бы поведение экспоненциального роста, и вы перераспределите только O (logN) раз. Более того, высококачественные реализации должны предварительно вычислять размер вставленного диапазона при наличии прямого или более сильного итератора, поэтому reserve не дает реальной выгоды.
T.C. 21.12.2018 02:14

Стоит отметить, что если вы создание вектора для этой цели, вы можете напрямую использовать конструктор вектора:

std::vector<std::pair<FirstType,SecondType>> vectorWordsList( mappedWordsList.begin(), mappedWordsList.end() );

В C++ 17 вы также можете опустить аргументы шаблона вектора, чтобы компилятор мог их вывести:

std::vector vectorWordsList( mappedWordsList.begin(), mappedWordsList.end() );

Если вы не хотите создать вектор итераторов, вам нужны скобки.

T.C. 20.12.2018 13:00

Другие вопросы по теме