find and replace a specific element of an array - c++

I am trying to locate "empty" in the array Bob, then after I find where empty is in the index i want to replace the word "empty" with "LEEROY JENKINS" Please forgive my lack of knowledge I am still very new to this and learning the best I can.
Problems:
int spindex() is not finding the correct index
empty is not being replaced
#include <string>
#include <iostream>
using namespace std;
int spindex(string x[], int n)
{
int i = 0;
int tindex;
while (x[i] != "empty" && i < n)
{
tindex = i;
i++;
}
return tindex;
}
int main()
{
string Bob[] = { "shaun", "empty", "tom", "empty", "chris", "sharon", "empty"};
int pim = 7;
int Q = spindex(Bob, pim);
Bob[Q] = "LEEROY JENKINS";
cout << Q << endl;
cout << Bob[Q] << endl;
for (int i = 0; i < 7; i++) {
cout << Bob[i] << endl;
}
}

This function
int spindex(string x[], int n)
{
int i = 0;
int tindex;
while (x[i] != "empty" && i < n)
{
tindex = i;
i++;
}
return tindex;
}
is wrong. Except when the first element of the array has the value "empty" the function returns the index before the index of the element that contains the string.
Also the order of the sub-conditions in the condition of the while loop is also wrong.
Write it the following way
size_t spindex( const std::string a[], size_t n )
{
size_t i = 0;
while ( i < n && a[i] != "empty" ) i++;
return i;
}
and call it like
size_t Q = spindex( Bob, sizeof( Bob ) / sizeof( *Bob ) );
A more general approach to write the function looks the following way
size_t spindex( const std::string a[], size_t n, const std::string &s )
{
size_t i = 0;
while ( i < n && a[i] != s ) i++;
return i;
}
And it can be called like
size_t Q = spindex( Bob, sizeof( Bob ) / sizeof( *Bob ), "empty" );
As an alternative you could use standard algorithm std::find declared in the header <algorithm>.

The problem is the way you constructed your loop:
while (x[i] != "empty" && i < n)
{
tindex = i;
i++;
}
First, i is 0. tindex gets set to 0, i gets set to 1.
Then the loop repeats, checking the condition. Oops! x[1] is "empty"! The loop ends and tindex is still 0.
That's why Q is 0 and why the wrong element is replaced.
Furthermore, you check i < n after trying to use x[i] (whoops).
You might as well just return i, since that is already the value you need:
int spindex(string x[], int n)
{
int i = 0;
while (i < n && x[i] != "empty") {
i++;
}
return i;
}
(live demo)
In my opinion, the entire problem would be better constructed thus:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string Bob[] = { "shaun", "empty", "tom", "empty", "chris", "sharon", "empty"};
auto it = std::find(std::begin(Bob), std::end(Bob), "empty");
if (it == std::end(Bob)) {
// No "empty" to replace!
return EXIT_FAILURE;
}
// Replace first "empty" with "BOB"
*it = "BOB";
// Here is our array now
std::cout << '[';
for (const auto el : Bob)
std::cout << el << ',';
std::cout << ']' << '\n';
}
// Output: [shaun,BOB,tom,empty,chris,sharon,empty,]
(live demo)

Related

Is this a wrong approach to find whether array is subarray of another array?

bool isSubset(int arr1[], int m,int arr2[], int n){
set<int> hashset;
for (int i = 0; i < m; i++){
hashset.insert(arr1[i]);
}
for (int i = 0; i < n; i++) {
if (hashset.find(arr2[i]) == hashset.end())
return false;
}
return true;
}
Is this correct method to find whether arr2 is sub array of arr1 or not
because sub array is contiguous part of array but this code is not checking for any order that's why I want to be sure.
Is this correct method to find whether arr2 is sub array of arr1 or not
No, it isn't. Your method doesn't consider the order of elements. It is more of a method to find whether a bunch of numbers (given in arr2) exist in an arr1.
For instance, if int arr1[] = {1, 2, 3} and int arr2[] = {2, 1}, the method you implemented will return true, while it should return false.
Here is how you would do it:
#include <iostream>
bool isSubset(int array[], int m, int subarray[], int n)
{
if (n > m)
return false;
for (int i = 0; i <= m-n; i++) {
int ii = i, j;
for (j = 0; j < n; j++)
if (subarray[j] != array[ii])
break;
else
ii++;
if (j == n)
return true;
}
return false;
}
Then call it like this:
int main()
{
int array[] = {1, 2, 3};
const int m = sizeof(array) / sizeof(*array);
int subarray1[] = {1, 2};
const int n1 = sizeof(subarray1) / sizeof(*subarray1);
int subarray2[] = {2, 1};
const int n2 = sizeof(subarray2) / sizeof(*subarray2);
std::cout << isSubset(array, m, subarray1, n1) << "\n"; // Will print 1
std::cout << isSubset(array, m, subarray2, n1) << "\n"; // Will print 0
}
You understood that the way your code is checking subarray is wrong.
A suggestion-
Use of C language style array in C++ is discouraged. Instead, you should use the appropriate standard container, provided in Containers library. You can use std::array container in place of plain C style array. Below is the sample code to check subarray:
#include <iostream>
#include <array>
#include <algorithm>
int main () {
std::array<int,12> arr1 {9,5,2,5,9,2,4,7,0,4,5,1};
std::array<int,3> arr2 {5,9,2};
bool res = false;
size_t pos = 0;
std::array<int,12>::iterator x;
while ((x = std::find(arr1.begin() + pos, arr1.end(), arr2[0])) != arr1.end()) {
size_t currpos = x - arr1.begin();
if ((arr1.size() - currpos >= arr2.size()) &&
((std::equal(arr1.begin() + currpos, arr1.begin() + currpos + arr2.size(), arr2.begin())))) {
res = true;
break;
}
pos = currpos + 1;
}
if (res) {
std::cout << "arr2 is subarray of arr1" << std::endl;
} else {
std::cout << "arr2 is not subarray of arr1" << std::endl;
}
return 0;
}

pushing strings into multidimensional vector c++

I am currently trying to separate a string by the number 2 and pushing the sub characters that i get into a 2d vector, the problem is that every time I try, I get a segmentation fault when I try to push the second row of characters in the vector. After trying a few things, I think the problem lies in the vector "some" after I clear the content of the vector. It seems to me that after the clearing, I am no longer able to push values into the vector. I hope that somebody has any suggestions because I am stuck.
std::string str = "11121112111";
std::vector<int> some;
std::vector<std::vector<int> > somemore;
for (unsigned int i = 0; i < str.length(); i++)
{
if (str[i] == '2')
{
somemore.push_back(some);
some.clear();
}
else
{
some.push_back(1);
}
}
for (unsigned int i = 0; i <= 3; i++)
{
for (unsigned int j = 0; j <= 3; j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
With c++11 and Boost you can make a much more elegant solution, without the need for loops with an incrementing index.
#include <vector>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
int main()
{
std::string str = "11121112111";
std::vector<std::string> string_vector;
boost::split(string_vector, str, boost::is_any_of("2"));
std::vector<std::vector<int>> int_vector;
for (auto& s : string_vector)
int_vector.push_back(std::vector<int>(s.size(), 1));
for (auto& v : int_vector)
for (auto& i : v)
std::cout << i << std::endl;
return 0;
}
I would change the last part:
for(unsigned int i = 0; i <=3; i++)
{
for(unsigned int j = 0; j <=3; j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
Into this:
for(unsigned int i = 0; i < somemore.size(); i++)
{
for(unsigned int j = 0; j < some.size(); j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
It is much safer.
As I already mentioned in comments, you have two problems in your code:
You are not pushing the last some into somemore because there is no 2 at the end of str.
Your last loops are too large - You have a 3x3 matrix but you expect a 4x4 since you go from 0 to 3.
By the way, since you are only counting ones, you don't need some:
std::string str = "11121112111";
std::vector<std::vector<int>> somemore;
size_t count = 0;
for (size_t = 0; i < str.length(); i++) {
if (str[i] == '2') {
somemore.push_back(std::vector<int>(count, 1));
count = 0;
}
else {
++count;
}
}
for (size_t i = 0; i < somemore.size(); ++i) {
for (size_t j = 0; j < somemore[i].size(); ++j) {
std::cout << somemore[i][j] << std::endl;
}
}
You could also replace the last two loops with iterators, or if you have c++11 available:
for (const auto &s: somemore) {
for (const auto &v: s) {
std::cout << v << std::endl;
}
}
In this loop
for(unsigned int i = 0; i < str.length(); i++)
{
if(str[i] == '2')
{
sommore.push_back(som);
som.clear();
}
else
{
som.push_back(1);
}
}
where it is not clear whether som is the vector declared like
std::vector<int> some;
^^^^^
the last part of the string
std::string str = "11121112111";
^^^
is ignored by vector sommore. So the vector contains only two elements that corresponds to two 2(s) in the string.
As result these loops
for(unsigned int i = 0; i <=3; i++)
{
for(unsigned int j = 0; j <=3; j++)
{
std::cout << sommore[i][j] << std::endl;
}
}
that use the magic number 3 have undefined behaviour.
Even if the vector and its sub-vectors contain 3 elements even in this case conditions i <=3 and j <=3 are wrong.
You can adopt the following approach shown in this demonstratrive program
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::vector<int>> v;
std::string str = "11121112111";
for ( std::string::size_type pos = 0; ( pos = str.find_first_not_of( "2", pos ) ) != std::string::npos; )
{
auto n = str.find( "2", pos );
if ( n == std::string::npos ) n = str.size();
v.push_back( std::vector<int>( n - pos, 1 ) );
pos = n;
}
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x;
std::cout << std::endl;
}
}
The program output is
111
111
111

Vector get only no repeating elements

I want to write a function which will return amount of no repeating digits. So far I have written a function which is iterating through char and collecting to vector all number, but the problem comes when I have to get from vector only non repeating digits.
My code:
int norepeat(char *word){
int i = 0;
int size = 0;
vector<int> tab;
while (word[i] != '\0'){
if (word[i] >= '0' && word[i] <= '9') {
int num = word[i];
tab.push_back(num);
sort(tab.begin(),tab.end());
unique(tab.begin(),tab.end());
size = tab.size();
}
++i;
}
return size;
}
EDIT:
Several examples how should it work:
norepeat("de32ge2sa3ds1") => 1
norepeat("defegtdsg") => 0
norepeat("12341234") => 0
norepeat("1yle2le49") => 4
Create a map of digits -> digit count.
Then iterate through the map and count the number of digits that have a count of 1.
int norepeat(char *word){
int i = 0;
std::map<char, int> m;
while (word[i] != '\0'){
if ( isdigit(word[i] )
m[word[i]]++;
++i;
}
int count = 0;
for ( auto& p : m )
{
if ( p.second == 1 )
++count;
}
return count;
}
When working with a compiler that does not support C++11, the for loop can be changed to:
std::map<char, int>::iterator iter = m.begin();
std::map<char, int>::iterator end = m.end();
for ( ; iter != end; ++iter )
{
if ( iter->second == 1 )
++count;
}
Nice thing of C++ is the ability to mix Plain-Old-Data pointers and libc functions and algorithms from the C++ standard template library: (note: uses some C++11 features)
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <ctype.h>
using namespace std;
size_t norepeat(const char* word) {
vector<char> digits;
vector<char>::iterator uniq;
// Filter the digits
copy_if(word, word+strlen(word), back_inserter(digits), ::isdigit);
// get the unique ones
sort(digits.begin(), digits.end());
uniq = unique(digits.begin(), digits.end());
// return amount
size_t uniques = std::distance(digits.begin(), uniq);
size_t duplicates = std::distance(uniq, digits.end());
return uniques - duplicates;
}
int main( void ) {
cout << norepeat("hello 123 world 124") << endl;
cout << norepeat("hello world") << endl;
return 0;
}
Outputs:
2
0
EDIT
Just for laughs: wrote a counting-output-iterator-class; it counts occurrences of values copied into it into a map of value -> unsigned int. Combined with the count_if algorithm (with C++ lambdas) the norepeat function itself is only three statements: a variable declaration, filtering the digits and return the result of the counting:
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <ctype.h>
using namespace std;
template <typename T>
struct counter : public iterator<output_iterator_tag, T> {
typedef map<T, unsigned int> counter_type;
counter(counter_type* ptr) : mapptr( ptr ) {}
// decorate with dereference and assignment
counter<T>& operator=( const T& t ) {
mapptr->operator[]( t )++;
return *this;
}
counter<T>& operator++() { return *this; }
counter<T>& operator*() { return *this; }
counter_type* mapptr;
};
size_t norepeat(const char* word) {
typename counter<char>::counter_type countert;
// Filter the digits
copy_if(word, word+strlen(word), counter<char>(&countert), ::isdigit);
// Count the ones that have a value of one
return count_if(countert.begin(), countert.end(),
[](const counter<char>::counter_type::value_type& kv) {
return kv.second==1; } );
}
int main( void ) {
cout << norepeat("hello 123 world 124") << endl;
cout << norepeat("hello world") << endl;
return 0;
}
Since my last answer was based on a misreading of the question, How about this?
int norepeat(const char *word){
int i = 0;
int size = 0;
int arr[10] = {0}; // there are only 10 unique possibilities,
// so we'll mark them when found
while (word[i] != '\0')
{
if (std::isdigit(word[i]))
{
int num = word[i] - '0'; // get numeric value of digit to use as index
arr[num]++; // count the number of times we've seen this digit
}
++i;
}
for (i = 0; i < 10; i++)
{
if (arr[i] == 1) // count all element seen only once
{
size++;
}
}
return size;
}
This gag is really limited because it will only work for decimal digits, but with a slight modification it could do upper or lower case characters. With a std::map... The possibilities are limitless! I'll add that for completeness in a second.
EDIT
The map version.
int norepeat(const char *word){
int i = 0;
int size = 0;
std::map<char, int> counts;
while (word[i] != '\0')
{
if (std::isdigit(word[i])) // could use any or no filtering logic here
{
counts[word[i]]++;
}
++i;
}
for (auto &count: counts)
{
if (count.second == 1) // count all element seen only once
{
size++;
}
}
return size;
}
int norepeat(char *word){
int i = 0;
int size = 0;
vector<int> tab;
while (word[i] != '\0'){
if (word[i] >= '0' && word[i] <= '9') {
int num = word[i];
tab.push_back(num);
}
++i;
}
size = std::distance( unique(tab.begin(),tab.end()), tab.end() );
return size;
}

Dynamic Nested Loops (C++)

Hello I am looking for a way to write this C++ Code in a general way, so that if a want 20 columns I will not have to write 20 for loops:
for(int i=1; i<6; i++) {
for(int j=i; j<6; j++) {
for(int k=j; k<6; k++) {
for(int m=k; m<6; m++) {
std::cout << i << j << k << m << std::endl;
}
}
}
}
It is important that my numbers follow a >= Order.
I am very grateful for any help.
This recursive function should work:
#include <iostream>
bool inc( int *indexes, int limit, int n )
{
if( ++indexes[n] < limit )
return true;
if( n == 0 ) return false;
if( inc( indexes, limit, n-1 ) ) {
indexes[n] = indexes[n-1];
return true;
}
return false;
}
int main()
{
const size_t N=3;
int indexes[N];
for( size_t i = 0; i < N; ++i ) indexes[i] = 1;
do {
for( size_t i = 0; i < N; ++i ) std::cout << indexes[i] << ' ';
std::cout << std::endl;
} while( inc( indexes, 6, N-1 ) );
return 0;
}
live example
The design here is simple. We take a std::vector each containing a dimension count and a std::vector containing a current index at each dimension.
advance advances the current bundle of dimension indexes by amt (default 1).
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
return;
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which gives us an advance function for generic n dimensional coordinates.
Next, a filter that tests the restriction you want:
bool vector_ascending( std::vector<size_t> const& v ) {
for (size_t i = 1; (i < v.size()); ++i) {
if (v[i-1] < v[i]) {
return false;
}
}
return true;
}
then a for loop that uses the above:
void print_a_lot( std::vector<size_t> counts ) {
for( std::vector<size_t> v(counts.size()); v < counts; advance(v,counts)) {
// check validity
if (!vector_ascending(v))
continue;
for (size_t x : v)
std::cout << (x+1);
std::cout << std::endl;
}
}
live example.
No recursion needed.
The downside to the above is that it generates 6^20 elements, and then filters. We don't want to make that many elements.
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
{
size_t min = indexes[i];
// enforce <= ordering:
for (size_t j = i+i; j < counts.size(); ++j) {
if (indexes[j]<min)
indexes[j]=min;
else
break; // other elements already follow <= transitively
}
assert(vector_ascending(indexes));
return;
}
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which should do it without the vector_ascending check in the previous version. (I left the assert in to do testing).
This function works for me, but do not call it with 20 if you want it to finish.
#include <list>
#include <iostream>
std::list<std::list<int>> fun (std::list<std::list<int>> inputlist, int counter)
{
if(counter == 0)
{
return inputlist;
}
else
{
std::list<std::list<int>> outputlist;
for(std::list<int> oldlist : inputlist)
{
for(int i = 1; i<6; i++)
{
std::list<int> newlist = oldlist;
newlist.push_back(i);
outputlist.push_back(newlist);
}
}
return fun(outputlist, counter - 1);
}
}
int main()
{
std::list<int> somelist;
std::list<std::list<int>> listlist;
listlist.push_back(somelist);
std::list<std::list<int>> manynumbers = fun (listlist,5);
for (std::list<int> somenumbers : manynumbers)
{
for(int k : somenumbers)
{
std::cout<<k;
}
std::cout<<std::endl;
}
return 0;
}
Same with Processing (java) here :
void loopFunction(int targetLevel, int actualLevel, int min, int max, String prefix){
/*
targetLevel is the wanted level (20 in your case)
actualLevel starts from 1
min starts from 1
max is the max number displayed (6 in your case)
prefix starts from blank
see usage bellow (in setup function)
*/
for(int m=min; m<max; m++) {
if(targetLevel==actualLevel)
{
println(prefix+ " " + m);
}
else
{
loopFunction(targetLevel, actualLevel+1,m,max,prefix+ " " + m);
}
}
}
void setup(){
loopFunction(10,1,1,6,"");
}
Well, I am not the fastest in writing answer... when I started there was no other answer. Anyhow, here is my version:
#include <iostream>
#include <vector>
using namespace std;
class Multiindex {
public:
typedef std::vector<int> Index;
Multiindex(int dims,int size) :
dims(dims),size(size),index(Index(dims,0)){}
void next(){
int j=dims-1;
while (nextAt(j) && j >= 0){j--;}
}
Index index;
bool hasNext(){return !(index[0]==size-1);}
private:
bool nextAt(int j){
index[j] = index[j]+1;
bool overflow = (index[j]==size);
if (!overflow && j < dims-1){std::fill(index.begin() + j + 1,index.end(),index[j]);}
return overflow;
}
int dims;
int size;
};
int main() {
Multiindex m(4,6);
while (m.hasNext()){
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
m.next();
}
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
return 0;
}

Generate the Cartesian Product of 2 vector<string>s In-Place?

If I want to get the Cartesian Product of these two vector<string>s:
vector<string> final{"a","b","c"};
vector<string> temp{"1","2"};
But I want to put the result in final, such that final would contain:
a1
a2
b1
b2
c1
c2
I'd like to do this without creating a temporary array. Is it possible to do this? If it matters, the order of final is not important.
You may try the following approach
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> final{ "a", "b", "c" };
std::vector<std::string> temp{ "1", "2" };
auto n = final.size();
final.resize( final.size() * temp.size() );
for ( auto i = n, j = final.size(); i != 0; --i )
{
for ( auto it = temp.rbegin(); it != temp.rend(); ++it )
{
final[--j] = final[i-1] + *it;
}
}
for ( const auto &s : final ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
a1 a2 b1 b2 c1 c2
Try the function cartesian:
#include <vector>
#include <string>
using namespace std;
void cartesian(vector<string>& f, vector<string> &o) {
int oldfsize = f.size();
f.resize(oldfsize * o.size());
for (int i = o.size() - 1; i>=0; i--) {
for (int j = 0; j < oldfsize; j++) {
f[i*oldfsize + j] = f[j] + o[i];
}
}
}
int main()
{
vector<string> f{"a","b","c"};
vector<string> temp{"1","2"};
cartesian(f, temp);
for (auto &s: f) {
printf("%s\n", s.c_str());
}
}
This works for me:
void testCartesianString(vector<string>& final,
vector<string>const& temp)
{
size_t size1 = final.size();
size_t size2 = temp.size();
// Step 1.
// Transform final to : {"a","a","b","b","c","c"}
final.resize(size1*size2);
for ( size_t i = size1; i > 0; --i )
{
for ( size_t j = (i-1)*size2; j < i*size2; ++j )
{
final[j] = final[i-1];
}
}
// Step 2.
// Now fix the values and
// change final to : {"a1","a2","b1","b2","c1","c2"}
for ( size_t i = 0; i < size1; ++i )
{
for ( size_t j = 0; j < size2; ++j )
{
final[i*size2+j] = final[i*size2+j] + temp[j];
cout << final[i*size2+j] << " ";
}
cout << endl;
}
}
This is just a personal preference option to Vald from Moscow's solution. I think it may be faster for dynamic arrays because there would be less branching. But I haven't gotten around to writing a timing test bench.
Given the inputs vector<string> final and vector<string> temp:
const auto size = testValues1.first.size();
testValues1.first.resize(size * testValues1.second.size());
for (int i = testValues1.first.size() - 1; i >= 0; --i){
testValues1.first[i] = testValues1.first[i % size] + testValues1.second[i / size];
}
EDIT:
Nope, this solution is slower not faster: http://ideone.com/e.js/kVIttT
And usually significantly faster, though I don't know why...
In any case, prefer Vlad from Moscow's answer