Как добавить элемент по элементу из двух векторов STL?
Вопрос довольно глупый, но мне нужно сделать это очень эффективным способом - это будет повторяться снова в моем коде. У меня есть функция, которая возвращает вектор, и я должен добавить возвращаемые значения в другой вектор, элемент за элементом. Довольно просто:
vector<double> result;
vector<double> result_temp
for(int i=0; i< 10; i++) result_temp.push_back(i);
result += result_temp //I would like to do something like that.
for(int i =0; i< result_temp.size();i++)result[i] += result_temp[i]; //this give me segfault
Математическая операция, которую я пытаюсь сделать, -
u [i] = u [i] + v [i] для всех i
Что можно сделать?
Спасибо
EDIT: добавлена простая инициализация, поскольку это не так. Как результат должен быть инициализирован?
Ответы
Ответ 1
Если вы пытаетесь добавить один vector
в другой, вы можете использовать что-то вроде следующего. Это одна из моих библиотек утилиты - две перегрузки operator+=
для std::vector
: один добавляет один элемент в vector
, другой добавляет целую vector
:
template <typename T>
std::vector<T>& operator+=(std::vector<T>& a, const std::vector<T>& b)
{
a.insert(a.end(), b.begin(), b.end());
return a;
}
template <typename T>
std::vector<T>& operator+=(std::vector<T>& aVector, const T& aObject)
{
aVector.push_back(aObject);
return aVector;
}
Если вы пытаетесь выполнить суммирование (т.е. создайте новый vector
, содержащий суммы элементов двух других vector
s), вы можете использовать что-то вроде следующего:
#include <algorithm>
#include <functional>
template <typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
{
assert(a.size() == b.size());
std::vector<T> result;
result.reserve(a.size());
std::transform(a.begin(), a.end(), b.begin(),
std::back_inserter(result), std::plus<T>());
return result;
}
Аналогичным образом можно реализовать перегрузку operator+=
.
Ответ 2
Конечно, похоже, что проблема заключается в доступе к значениям result
, которых не существует. tzaman показывает, как инициализировать результат до 10 элементов, каждый со значением 0.
Теперь вам нужно вызвать функцию transform
(из <algorithm> ), применяя объект функции plus
(от < функциональный > ):
std::transform(result.begin(), result.end(), result_temp.begin(),
result.begin(), std::plus<double>());
Итерирует через result
и result_temp
, применяет plus
, который добавляет удвоения, и возвращает сумму обратно в result
.
Ответ 3
Конкретный пример ответа Джона Рида:
std::array<double,3> a = {1, 2, 3};
std::array<double,3> b = {4, 5, 6};
std::transform(a.begin( ), a.end( ), b.begin( ), a.begin( ),std::plus<double>( ));
ASSERT_TRUE(a[0] == 5);
ASSERT_TRUE(a[1] == 7);
ASSERT_TRUE(a[2] == 9);
Ответ 4
Сначала нужно инициализировать result
ко всем нулям; просто объявление переменной фактически не выделяет никаких элементов.
Попробуйте следующее:
vector<double> result(10); // default-initialize to 10 elements
vector<double> result_temp;
for(int i=0; i< 10; i++)
result_temp.push_back(i);
for(int i =0; i< result_temp.size();i++)
result[i] += result_temp[i];
Ответ 5
Я с @James McNellis - этот код кажется правильным, если result
и result_temp
имеют одинаковую длину.
Также - почему вы объявили result
, но используете переменную result_v
- это то, как код написан на самом деле? Если да, то проблема
Ответ 6
Код кажется прекрасным, но моим первым наклонением было бы изменить любой код, заполняющий вектор, значениями, чтобы добавить к значениям в первом векторе, чтобы взять ссылку на первый вектор и добавить непосредственно к нему, а не создавать новый вектор, который возвращается. Это просто неэффективно.
Если вы не можете изменить функцию таким образом, возможно, вы можете изменить ее так, чтобы она ссылалась на вектор, который он очищает, а затем вставляет значения в так, чтобы вы не копировали векторы. Это может стать дорогостоящим, если вы делаете это много.
Еще одна проблема, если вы пытаетесь сделать это как можно быстрее, вы должны использовать pre-increment с итераторами, а не с последующим приращением. Временное создание post-increment не может быть оптимизировано при работе с перегруженными операторами, а не с встроенными типами. Таким образом, вы продолжаете создавать и уничтожать временную каждую итерацию цикла. EDIT: Как было отмечено в комментариях, вы используете здесь индексы, а не итераторы (я, очевидно, не уделял достаточного внимания), поэтому этот немного советов здесь не применим. Однако в тех случаях, когда вы используете итераторы, он все еще действителен.
Кроме того, если вы пытаетесь добавить все элементы двух векторов togther, то, что у вас есть, вероятно, является таким же эффективным решением, какое вы собираетесь получить. Есть лучшие способы, если вы беспокоитесь о том, чтобы вставить элементы одного вектора в другой, но если вы просто добавляете свои ценности вместе, то, что у вас хорошо выглядит. Я ожидал бы, что использование любых алгоритмов STL будет в лучшем случае столь же быстрым и, скорее всего, медленным из-за дополнительных вызовов функций, но вам, вероятно, придется профилировать его, чтобы быть уверенным.
Ответ 7
Если ваш код прерван, тогда проблема корректности, а не проблема с эффективностью.
Чтобы достичь "u [i] = u [i] + v [i] для всех i", я бы сделал в основном то, что вы сделали:
assert(u.size() == v.size()); // will fail with your initialization code, since
// your "result" has size 0, not size 10.
// perhaps do u.resize(v.size());
for (size_t i = 0; i < u.size(); ++i) {
u[i] += v[i];
}
Если вы действительно заботитесь о производительности своей программы (т.е. вы написали базовую версию, и она настолько медленная, что ваша программа не выполняет некоторые требования, и вы доказали, что это код, в котором большую часть времени), вы можете попробовать:
- включение большого количества оптимизации в ваш компилятор (на самом деле, я обычно делаю это по умолчанию, даже если нет проблемы с производительностью),
- использование итераторов вместо индексов (редко имеет большое значение, но достаточно просто сравнить их),
- немного развернуть цикл (может сделать целесообразную разницу в скорости, но это довольно чувствительно к конкретному случаю и поощряет ошибки кодирования).
- глядя на специфические для платформы инструкции SIMD, а не на С++. Затем используйте встроенные ассемблерные или компиляторы для этих инструкций.
Тем не менее, вы не беспокоитесь о производительности, прежде чем ваш код будет правильным;-). "Заставьте это работать, сделайте все правильно, сделайте это быстро" - это разумный девиз, хотя часто вам не нужно идти на шаг 3.
std::valarray
имеет ровно operator+=
, который вы хотите. Помните, что перед заменой всех ваших векторов валерианами, это не обязательно означает "более эффективный", чем простой цикл. Я не знаю, как серьезно исполнители берут valarray
. Вы всегда можете посмотреть источник в своей реализации. Я также не знаю, почему арифметическая функция с несколькими данными valarray
не была определена как часть vector
, но обычно есть причина.