Wie verkette ich zwei std::vector
s?
1. Anruf haben 2. Überlast
Wie verkette ich zwei std::vector
s?
Hier ist eine allgemeine Lösung, die die Move-Semantik von C++11 verwendet:
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
if (lhs.empty()) return rhs;
if (rhs.empty()) return lhs;
std::vector<T> result {};
result.reserve(lhs.size() + rhs.size());
result.insert(result.cend(), lhs.cbegin(), lhs.cend());
result.insert(result.cend(), rhs.cbegin(), rhs.cend());
return result;
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, const std::vector<T>& rhs)
{
lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
return std::move(lhs);
}
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, std::vector<T>&& rhs)
{
rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
return std::move(rhs);
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, std::vector<T>&& rhs)
{
if (lhs.empty()) return std::move(rhs);
lhs.insert(lhs.cend(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
return std::move(lhs);
}
Beachten Sie, dass dies ein Unterschied ist zu append
in eine vector
.
Dieser Codeschnipsel kann das Problem zwar lösen, erklärt aber nicht, warum oder wie er die Frage beantwortet. Bitte fügen Sie eine Erklärung für Ihren Code ein Das trägt wirklich dazu bei, die Qualität Ihres Beitrags zu verbessern. Flaggenleger / Prüfer: Bei reinen Code-Antworten wie dieser sollten Sie eine negative Bewertung abgeben, nicht löschen! (Hinweis: Diese Antwort könnte tatsächlich so einfach sein, dass eine Erklärung und damit eine Herabstufung unnötig ist. Sie sollten dennoch eine Erklärung hinzufügen, um weitere NAA/VLQ-Flags zu vermeiden).
Sie können Ihre eigene Vorlage für + Operator erstellen:
template <typename T>
inline T operator+(const T & a, const T & b)
{
T res = a;
res.insert(res.end(), b.begin(), b.end());
return res;
}
Als Nächstes: Verwenden Sie einfach +:
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
Dieses Beispiel ergibt eine Ausgabe:
1 2 3 4 5 6 7 8
Ich habe diese Funktion implementiert, die eine beliebige Anzahl von Containern verkettet, indem sie von rvalue-Referenzen ausgeht und ansonsten kopiert
namespace internal {
// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if
// appropriate
template<typename Target, typename Head, typename... Tail>
void AppendNoReserve(Target* target, Head&& head, Tail&&... tail) {
// Currently, require each homogenous inputs. If there is demand, we could probably implement a
// version that outputs a vector whose value_type is the common_type of all the containers
// passed to it, and call it ConvertingConcatenate.
static_assert(
std::is_same_v<
typename std::decay_t<Target>::value_type,
typename std::decay_t<Head>::value_type>,
"Concatenate requires each container passed to it to have the same value_type");
if constexpr (std::is_lvalue_reference_v<Head>) {
std::copy(head.begin(), head.end(), std::back_inserter(*target));
} else {
std::move(head.begin(), head.end(), std::back_inserter(*target));
}
if constexpr (sizeof...(Tail) > 0) {
AppendNoReserve(target, std::forward<Tail>(tail)...);
}
}
template<typename Head, typename... Tail>
size_t TotalSize(const Head& head, const Tail&... tail) {
if constexpr (sizeof...(Tail) > 0) {
return head.size() + TotalSize(tail...);
} else {
return head.size();
}
}
} // namespace internal
/// Concatenate the provided containers into a single vector. Moves from rvalue references, copies
/// otherwise.
template<typename Head, typename... Tail>
auto Concatenate(Head&& head, Tail&&... tail) {
size_t totalSize = internal::TotalSize(head, tail...);
std::vector<typename std::decay_t<Head>::value_type> result;
result.reserve(totalSize);
internal::AppendNoReserve(&result, std::forward<Head>(head), std::forward<Tail>(tail)...);
return result;
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
10 Stimmen
Die gegebenen Antworten sind nicht wirklich zusammenhängend. Sie fügen eine Kopie an. Es könnte (aus Gründen der Effizienz) sinnvoll sein, eine std::vector concatenate-Methode zu erstellen, allerdings würde dies eine ausgeklügelte gemeinsame Nutzung der Verwaltung der Knoten erfordern, und das ist wahrscheinlich der Grund, warum dies noch nicht geschehen ist.
16 Stimmen
@FauChristian: Nein, unter Effizienzgesichtspunkten kann es keinen Nutzen geben. Der Vektorspeicher muss kontinuierlich sein, also ist das, was Sie vorschlagen, unmöglich. Wenn Sie "eine ausgeklügelte gemeinsame Nutzung der Verwaltung der Knoten" wollten und die Vektorklasse auf diese Weise ändern würden, würden Sie bei einer Deque landen. Selbst dann ist es sehr schwierig, den Speicher in der vorgeschlagenen Weise wiederzuverwenden, auch wenn es allmählich ein wenig praktikabler wäre. Ich glaube nicht, dass es derzeit implementiert ist. Die Hauptsache ist, dass in einem solchen Sharing von Management-Knoten (eine deque) der Endknoten teilweise leer sein könnte.
18 Stimmen
Bin ich der Einzige, der sich fragt, warum dies nicht als
a + b
oa.concat(b)
in der Standardbibliothek? Vielleicht wäre die Standardimplementierung suboptimal, aber nicht jede Array-Verkettung muss mikro-optimiert sein58 Stimmen
Jahre der Entwicklung, das fortschrittlichste Operator-Overloading aller Mainstream-Sprachen, ein Templating-System, das die Komplexität der Sprache verdoppelt, und dennoch lautet die Antwort nicht v = v1 + v2;
7 Stimmen
Ich vermute, dass die STL die Sprache nicht überspezifizieren wollte, für den Fall, dass der Operator etwas anderes tun sollte, z. B. Kraftvektoren in einem Physikmodell hinzufügen. In diesem Fall könnten Sie überladen wollen
forceVector1 + forceVector2
um in klarem, prägnantem Code punktweise zu addieren.3 Stimmen
@Spike0xff, v = v1 + v2 hat in der Mathematik eine Bedeutung, die nichts mit Verkettung zu tun hat. Es hat auch einige Anforderungen, um berechenbar zu sein. Ich würde eher eine Append-Methode vorschlagen (eine Abkürzung dessen, was man mit
insert
) oder eine Push-Back-Überlastung.