Подтвердить что ты не робот

Как добавить элемент по элементу из двух векторов 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: добавлена ​​простая инициализация, поскольку это не так. Как результат должен быть инициализирован?

4b9b3361

Ответ 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, но обычно есть причина.