Есть ли элегантный способ обойти 2 карты и сравнить значения (карты имеют одинаковый тип)

скажем, у меня есть 2 карты:

map<int,vector<int>> id2courses;
map<int,vector <int>> id2allowed_courses;

И я хотел бы для каждого ключа (идентификатора) посмотреть, содержит ли список курсов только те курсы, которые разрешены для этого идентификатора. Это можно легко сделать с помощью цикла for, но я хотел бы использовать тот факт, что std::map упорядочен, то есть я хотел бы продвигаться по обеим картам (увеличивая итератор с меньшим ключом), и когда я нажимаю равные клавиши, тогда Я хотел бы сделать сравнения. Я знаю, что могу сделать это с помощью нетривиального цикла while, но мне интересно, есть ли встроенный способ STL для этого


person NoSenseEtAl    schedule 14.02.2013    source источник
comment
Для ключа на разрешенной карте не обязательно должна быть запись на другой карте, или нет?   -  person leemes    schedule 14.02.2013
comment
Вы можете проверить std::set_intersection.   -  person Some programmer dude    schedule 14.02.2013
comment
@leemes нет, допустим, меня волнует общий случай, нет гарантии, что все .first одинаковы.   -  person NoSenseEtAl    schedule 14.02.2013


Ответы (2)


Использование std::set_intersection — это своего рода хак:

map<int,vector<int>> id2courses;
map<int,vector <int>> i2allowed_courses;

set_intersection(id2courses.begin(), id2courses.end(),
                 i2allowed_courses.begin(), i2allowed_courses.end(),
                 null_output_iterator(),
                 compare_and_do_something_if_same_key);

null_output_iterator взят из вопроса Отказ от вывода функции, которой требуется итератор вывода.

compare_and_do_something_if_same_key будет передаваться pair<const int, vector<int>> с каждой карты. Если ключи равны, вы можете выполнить обработку, которую хотите. Вам также необходимо вернуть логическое значение для представления порядка элементов:

bool compare_and_do_something_if_same_key(
    pair<const int, vector<int>& a, pair<const int, vector<int>& b)
{
    if(a.first == b.first) {
        doProcessing(a, b);
    }
    return a.first < b.first;
}

Предостережение Emptor: в документации сказано, что функция сравнения не должна изменять сравниваемые объекты. Я понимаю, что это означает, что нельзя изменять таким образом, чтобы вызвать проблемы с заказом. Поскольку вы не упорядочиваете значение second в pair, я не думаю, что это имеет большое значение.

изменить для удобочитаемости:

Это можно было бы обернуть в именованную функцию:

template<typename Map, typename KeyValueProcessor> 
void process_values_for_matching_keys(
    Map& map1, Map& map2, KeyValueProcessor& keyValueProcessor);

И используется как:

process_pairs_for_matching_keys(id2courses, i2allowed_courses, doProcessing);
person Peter Wood    schedule 14.02.2013
comment
Интересно, что использование std::merge вместо set_intersection приводит к тем же результатам, но, возможно, немного менее эффективен, так как есть больше назначений для null_output_iterator. - person Peter Wood; 14.02.2013

Вы можете использовать set_intersection(), но эта реализация, хотя и легче читается, будет быть не так хорошо выполнять. Я бы использовал цикл и увеличил два итератора по двум картам. Я не думаю, что есть более быстрое решение. Даже если есть что-то встроенное, оно будет работать так же хорошо, как и это наивное решение.

person Ivaylo Strandjev    schedule 14.02.2013
comment
Почему бы ему не работать хорошо? - person Peter Wood; 14.02.2013
comment
set_intersection выполняет одну итерацию по обоим контейнерам. Затем ему нужно будет сделать еще один, чтобы выполнить проверку каждого из элементов на заданное свойство. OP может сделать все это за одну итерацию. - person Ivaylo Strandjev; 14.02.2013
comment
Я представлял себе взлом функции сравнения для выполнения действия. Смотри мой ответ - person Peter Wood; 14.02.2013
comment
@PeterWood Я бы бросил вызов, если бы это было более элегантно, чем реализация двух циклов. Тем не менее полезно знать, что есть такая опция. - person Ivaylo Strandjev; 14.02.2013
comment
Заданное пересечение требует, чтобы значения в списке были отсортированы. И Op хочет сравнить значения, когда есть совпадение в ключах. Таким образом, даже если вы используете заданное пересечение, это не уменьшает усилий при обходе карт. - person Vijay; 14.02.2013
comment
@sarathi, мне кажется, что не все ключи присутствуют на обеих картах, поэтому set_intersection оставит только ключи, присутствующие на обеих картах. Это сделает цикл более элегантным — два итератора, которые вы увеличиваете на каждой итерации. Обратите внимание, что мой ответ по-прежнему сосредоточен на том факте, что лучший вариант OP - выполнять циклы, а не использовать set_intersection. - person Ivaylo Strandjev; 14.02.2013
comment
но Оп не упомянул о сортировке. Если список значений не отсортирован, то вам нужно снова отсортировать, прежде чем передавать их в set_intersection. Что снова потребует много усилий на процессоре. - person Vijay; 14.02.2013
comment
@sarathi, пожалуйста, обратите внимание, что у него есть карта. Я предлагаю set_intersection для ключей карты. but I would like to exploit the fact that std::map is ordered, aka I would like to advance in both maps - person Ivaylo Strandjev; 14.02.2013