How to search vector element and replace it? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
void print(vector<string> v) {
for (unsigned int i = 0; i < v.size(); i++) {
cout << "[" << i << "] " << v[i] << "\n";
}
}
int main(){
vector<string> v(5);
v[0] = "Egg";
v[1] = "Milk";
v[2] = "Sugar";
v[3] = "Chocolate";
v[4] = "Flour";
print(v);
system("pause");
}
How do I make a loop that searches for the item, "sugar" and replace it with "honey."? Sry, im new to vectors

If you want to replace the first instance of the string (if it exists) you can use std::find then assign to the iterator that is returned.
std::vector<std::string> v {"Egg", "Milk", "Sugar", "Chocolate", "Flour"};
auto itMatch = std::find(v.begin(), v.end(), "Sugar");
if (itMatch != v.end())
*itMatch = "Honey";
If you'd like to replace all instances
std::replace(v.begin(), v.end(), "Sugar", "Honey");

You can use the standard alfgorithm std::find. For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour"
};
const char *src = "Sugar";
const char *dsn = "Honey";
auto it = std::find( v.begin(), v.end(), src );
if ( it != v.end() ) *it = dsn;
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
Egg Milk Honey Chocolate Flour
If you want to replace all occurences of "Sugar" then you can use the standard algorithm std::replace.
For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour", "Sugar"
};
const char *src = "Sugar";
const char *dsn = "Honey";
std::replace( v.begin(), v.end(), src, dsn );
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
Egg Milk Honey Chocolate Flour Honey
If you mean the substitution only in the function print within the loop then the function can look the following way
#include <iostream>
#include <vector>
#include <string>
void print( const std::vector<std::string> &v,
const std::string &src = "Sugar",
const std::string &dsn = "Honey" )
{
for ( std::vector<std::string>::size_type i = 0; i < v.size(); i++ )
{
std::cout << "[" << i << "] " << ( v[i] == src ? dsn : v[i] ) << "\n";
}
}
int main()
{
std::vector<std::string> v =
{
"Egg", "Milk", "Sugar", "Chocolate", "Flour"
};
print( v );
return 0;
}
Its output is
[0] Egg
[1] Milk
[2] Honey
[3] Chocolate
[4] Flour

Related

map,vector in c++ [duplicate]

This question already has answers here:
How do I print out the contents of a vector?
(31 answers)
Closed 2 years ago.
error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘std::pair<const std::__cxx11::basic_string, std::vector >’)
i want to same key and mutiple values, for example key is 10 values are 2,3,4
but "*iter" is wrong..
how to cout map,vector in c++?
In your code snippet the value of the expression *iter is an object of the type std::pair<std::string, std::vector<int>> for which the operator << is not defined.
And the error message
error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and
‘std::pair<const std::__cxx11::basic_string, std::vector >’)
says about this.
The simplest way is to use the range-based for loop.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <vector>
#include <map>
int main()
{
std::map<std::string, std::vector<int>> m;
m["10"].assign( { 2, 3, 4 } );
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( const auto &item : p.second )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
return 0;
}
The program output is
10: 2 3 4
If you want to write ordinary for-loops using iterators then the loops can look the following way.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <iterator>
int main()
{
std::map<std::string, std::vector<int>> m;
m["10"].assign( { 2, 3, 4 } );
for ( auto outer_it = std::begin( m ); outer_it != std::end( m ); ++outer_it )
{
std::cout << outer_it->first << ": ";
for ( auto inner_it = std::begin( outer_it->second );
inner_it != std::end( outer_it->second );
++inner_it )
{
std::cout << *inner_it << ' ';
}
std::cout << '\n';
}
return 0;
}
Again the program output is
10: 2 3 4
I suggest using structured bindings and range-based for loops:
std::map<std::string,std::vector<int>> m;
for (auto&[str, vec] : m) { // bind str to "first" in the pair and vec to "second"
std::cout << str << ':';
for(auto lineno : vec) std::cout << ' ' << lineno;
std::cout << '\n';
}
You can define how to print things via std::ostream like this:
#include <iostream>
#include <map>
#include <vector>
#include <string>
// define how to print std::pair<std::string, std::vector<int>>
std::ostream& operator<<(std::ostream& stream, const std::pair<std::string, std::vector<int>>& pair) {
stream << "(" << pair.first << ", {";
bool first = true;
for (int e : pair.second) {
if (!first) stream << ", ";
stream << e;
first = false;
}
stream << "})";
return stream;
}
int main(void) {
std::string yytext = "hoge";
int lineno = 42;
// below is copied from the question
std::map<std::string,std::vector<int>> m;
m[yytext].push_back(lineno);
std::map<std::string,std::vector<int>>::iterator iter;
for (iter=m.begin(); iter!=m.end(); iter++){
std::cout<<iter->first<<":"<<*iter<<std::endl;}
}

Finding permutations and combinations of elements in the array for 2 elements each

I am trying to find the permutation and combination of elements with 2 objects each - nC2 or nP2. I can find the combinations by the below code. Is there any elegant way to rewrite this? Also, is there any way to find permutations? The below is just an example, My datasets consists of close to 2000 elements. So, speed is a factor too.
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> array = {"a", "b", "c", "d", "e"};
std::vector<std::string>::iterator it = array.begin();
for ( ; it < array.end(); it++ ) {
for (std::vector<std::string>::iterator it_next = it+1 ; it_next < array.end(); it_next++ ) {
std::cout << *it << *it_next << "\n";
}
}
}
Program output -
gcc version 4.6.3
ab
ac
ad
ae
bc
bd
be
cd
ce
de
Relative to your initial code for combinations, you can improve the performance by going through the vector using [], instead of iterators:
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
int main() {
std::vector<std::string> array = { "a", "b", "c", "d", "e" };
int current;
int next;
for (current = 0; current < array.size(); ++current)
{
for (next = current + 1; next < array.size(); ++next)
{
std::cout << array[current] << array[next] << "\n";
}
}
return 0;
}
Well, if you just want the permutation of all combinations, it is real simple as you only have two items in each combination. So simply reverse the printing - like:
std::vector<std::string> array = {"a", "b", "c", "d", "e"};
std::vector<std::string>::iterator it = array.begin();
for ( ; it < array.end(); it++ ) {
for (std::vector<std::string>::iterator it_next = it+1 ; it_next < array.end(); it_next++ ) {
std::cout << *it << *it_next << "\n";
// Print the permutation - simply swap the order
std::cout << *it_next << *it << "\n";
}
}
}
Old answer where I misunderstood what OP wanted
Also, is there any way to find permutations?
yes, it can be done in several ways but std::next_permutation seems a good fit.
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
// Print the vector
void pv(const std::vector<std::string>& v)
{
for (const auto& s : v)
{
std::cout << s << " ";
}
std::cout << std::endl;
}
int main()
{
std::vector<std::string> array = {"a", "b", "c"};
std::sort(array.begin(), array.end());
do
{
pv(array);
} while(std::next_permutation(array.begin(), array.end()));
}
Output:
a b c
a c b
b a c
b c a
c a b
c b a

c++ how to replace a string in an array for another string

I am trying a short code that uses an array, I basically want to replace the word hate for love when I call my function WordReplace but I keep printing the same thing:
I don't love c++
I don't love c++
I have tried different things but I am not sure what is wrong
#include <iostream>
#include <string>
using namespace std;
void WordReplace(string*x, int start, int end, string g, string w)
{
for (int z = start; z <= end; z++)
{
if (x[z] == g)
x[z] == w;
cout << x[z]<<" ";
}
}
int main()
{
string x[4] = {"I", "don't", "hate", "c++"};
for (int i = 0; i < 4; i++)
{
cout << x[i] << " ";
}
cout << endl;
WordReplace(x, 0, 3, "hate", "love");
cout << endl;
return 0;
}
Just use std::replace:
std::string x[] = {"I", "don't", "hate", "c++"};
std::replace( std::begin( x ), std::end( x ), "hate", "love" );
live example
You have c++. Use proper containers (e.g. std::vector).
#include <string>
#include <vector>
#include <iostream>
using namespace std;
void WordReplace(vector<string> &sentence, string search_string,
string replace_string) {
for (auto &word : sentence) {
if (word == search_string)
word = replace_string;
}
}
int main() {
vector<string> sentence{"I", "don't", "hate", "c++"};
for (const auto word : sentence)
cout << word << " ";
cout << endl;
WordReplace(sentence, "hate", "love");
for (const auto word : sentence)
cout << word << " ";
cout << endl;
return 0;
}
or even better, don't reinvent the wheel
std::vector<std::string> x {"I", "don't", "hate", "c++"};
std::replace( x.begin(), x.end(), "hate", "love" );
If you want to assign a new value to a variable you need the following syntax:
myVar = myValue;
This will change the value of myVar to myValue.
This construction:
myVar == myValue
is a comparison and is treated as a bool, since it returned true(if myVar equals myValue) and False (if they are not equal). The construction doesn't change the value of myVar or myValue.
In your case you need to replace x[z] == w by x[z] = w, as suggested by Igor

Cache locality with unique_ptr

I have a vector of custom classes (std::string just for example).
The vector is large and I iterate through often, so I rely on cache locality.
I also have one raw pointer which points at one of the vector elements.
Now is the trick:
The vector is sorted from time to time, so the raw pointer loose the actual pointed element value, and will point to some random element value.
Here is an example to illustrate the same:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<string> v = {"9","3", "8", "7", "6", "5", "1", "4", "2"};
string* rs = &v[7]; //point to the 7th element
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i];
cerr << endl;
cerr << "Referenced string: " << rs->c_str() << endl;
cerr << "Sort ..." << endl;
sort(v.begin(), v.end(), [](const string& a, const string& b)
{
if (a < b)
return true;
else
return false;
}
);
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i];
cerr << endl;
cerr << "Referenced string: " << rs->c_str() << endl;
cin.get();
return 0;
}
Output:
938765142
Referenced string before sort : 4
Sort ...
123456789
Referenced string after sort : 8
Since I wish the rs pointer to keep pointing to the 7th element value (which is 4) even after the sort, I came up with the following solution (vector of pointers):
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<unique_ptr<string>> v;
v.resize(9);
v[0] = make_unique<string>("9");
v[1] = make_unique<string>("3");
v[2] = make_unique<string>("8");
v[3] = make_unique<string>("7");
v[4] = make_unique<string>("6");
v[5] = make_unique<string>("5");
v[6] = make_unique<string>("1");
v[7] = make_unique<string>("4");
v[8] = make_unique<string>("2");
string* rs = v[7].get();
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i]->c_str();
cerr << endl;
cerr << "Referenced string before sort: " << rs->c_str() << endl;
cerr << "Sort ..." << endl;
sort(v.begin(), v.end(), [](const unique_ptr<string>& a, const unique_ptr<string>& b)
{
if (*a < *b)
return true;
else
return false;
}
);
for (size_t i = 0; i < v.size(); ++i)
cerr << v[i]->c_str();
cerr << endl;
cerr << "Referenced string after sort: " << rs->c_str() << endl;
cin.get();
return 0;
}
Output:
938765142
Referenced string before sort: 4
Sort ...
123456789
Referenced string after sort: 4
While this latter solution works, there is a price: I have lost the cache locality of my vector, since I store pointers in it, rather than the actual objects.
Is there a way to maintain cache locality (e.g.: store my actual objects in the vector), and somehow manage to rs pointer to keep track where its pointed value wander around due to the sorts?
Or from the other perspective, is there a way to achieve cache locality with the vector of pointers?
Solution from Pubby, thanks!:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <memory>
using namespace std;
int main()
{
vector<string> data = { "d","e", "f", "g", "i", "b", "c", "a", "h" };
vector<int> indexes = {0,1,2,3,4,5,6,7,8};
int si = 6;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << indexes[i];
cerr << endl;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << data[indexes[i]];
cerr << endl;
cerr << "Referenced string before sort: " << data[si] << endl;
cerr << "Sort ..." << endl;
sort(indexes.begin(), indexes.end(), [&](const int a, const int b)
{
return data[a] < data[b];
}
);
for (size_t i = 0; i < indexes.size(); ++i)
cerr << indexes[i];
cerr << endl;
for (size_t i = 0; i < indexes.size(); ++i)
cerr << data[indexes[i]];
cerr << endl;
cerr << "Referenced string after sort: " << data[si] << endl;
cin.get();
return 0;
}
You can increase locality by storing the strings in a vector which doesn't change, and then store a vector of pointers/indexes to these strings.
Like this:
vector<string> data = {"9","3", "8", "7", "6", "5", "1", "4", "2"};
vector<unsigned> indexes(data.size());
std::iota(indexes.begin(), indexes.end(), 0u);
To sort your data you'd sort indexes using a custom comparator function which retrieves the values from data and compares them. Remember: indexes can change, but data should not!
sort(indexes.begin(), indexes.end(), [&](unsigned a, unsigned b)
{
return data[a] < data[b];
});
Just an idea: Instead of storing std::string in the vector, just append the character arrays of each string to a std::vector<char>.
This packs the strings closely together in memory, improving locality even better than std::string with small string optimization. It will also give better results if the strings exceed the max. size for small string optimization.
For sorting, store index and size of each string in a 2nd vector similar to Pubbys suggestion.
Of course this only works if the string length doesn't need to change dynamically. Otherwise you would have to rebuild the vector<char>.
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <string_view>
using namespace std;
using IndexAndSize = pair<size_t,size_t>;
void push_and_index( vector<char>& v, vector<IndexAndSize>& vi, string_view s )
{
vi.emplace_back( v.size(), s.size() );
v.insert( end(v), begin(s), end(s) );
}
string_view make_string_view( vector<char> const& v, IndexAndSize is )
{
return { v.data() + is.first, is.second };
}
int main()
{
vector<char> v;
vector<IndexAndSize> vi;
push_and_index( v, vi, "foo" );
push_and_index( v, vi, "bar" );
push_and_index( v, vi, "foobar" );
push_and_index( v, vi, "barfoo" );
sort( begin(vi), end(vi), [&]( IndexAndSize a, IndexAndSize b )
{
return make_string_view( v, a ) < make_string_view( v, b );
});
for( IndexAndSize is : vi )
{
cout << make_string_view( v, is ) << endl;
}
}
Live demo on Coliru.
Note: C++17's string_view is used only to help with the sorting and output, it's not crucial for this idea.

Iteration into std::vector<string>

I have a vector of string parameters...
|name1|value1|name2|value2|...
I wanna iterate and cache the name into a string and add it into a vector of names and make the same thing with the value. They are in a std::vector<string>.
I do it:
std::vector<string> names;
std::vector<string> values;
std::vector<string>::iterator pit = p.begin();
while(pit != p.end()){
string name = *pit;
pit++;
string value = *pit;
pit++;
names.push_back(name);
values.push_back(value);
}
But it returns an access violation in vector. It is accessing a bad location returning a <BadPtr>.
How to do this iteration?
Does it have a way of do it using for each?
Check this out:
std::vector<string> names;
std::vector<string> values;
std::vector<string>::iterator pit = p.begin();
while(pit != p.end()){
string name = *pit;
pit++;
if(pit == p.end())
break;
string value = *pit;
pit++;
names.push_back(name);
values.push_back(name);
}
As i said in my comment that problem could be, you didn't put any checking after incrementing pit second time.
Here is a demonstrative program that shows how it can be done using standard algorithm std::partition_copy
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<std::string> p = { "name1", "value1", "name2", "value2" };
std::vector<std::string> names;
std::vector<std::string> values;
names.reserve( ( p.size() + 1 ) / 2 );
values.reserve( p.size() / 2 );
unsigned int i = 0;
std::partition_copy( p.begin(), p.end(),
std::back_inserter( names ),
std::back_inserter( values ),
[&]( const std::string & ) { return i ^= 1; } );
for ( const auto &s : p ) std::cout << s << ' ';
std::cout << std::endl;
for ( const auto &s : names ) std::cout << s << ' ';
std::cout << std::endl;
for ( const auto &s : values ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
name1 value1 name2 value2
name1 name2
value1 value2
The same can be done using the range based for statement
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> p = { "name1", "value1", "name2", "value2" };
std::vector<std::string> names;
std::vector<std::string> values;
names.reserve( ( p.size() + 1 ) / 2 );
values.reserve( p.size() / 2 );
unsigned int i = 0;
for ( const std::string &s : p )
{
if ( i ^= 1 ) names.push_back( s );
else values.push_back( s );
}
for ( const auto &s : p ) std::cout << s << ' ';
std::cout << std::endl;
for ( const auto &s : names ) std::cout << s << ' ';
std::cout << std::endl;
for ( const auto &s : values ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
Thus your loop can look more simpler like
unsigned int i = 0;
for ( const std::string &s : p )
{
if ( i ^= 1 ) names.push_back( s );
else values.push_back( s );
}
As you see the body of the loop consists only from two statements instead of six or eight statements if to use your approach.