Filling a new array of ints with part of a different array

Hi,

I have an array with x values and 0 values. How can I fill a new array with just the x values?

e.g.
num[1, 0, 4, 0, 0, 5];
newNums[1, 4, 5];

1
2
3
4
5
6
7
8
9
  for (int i = 0; i < y.length(); i++){

        if (num[i] != 0){
            individualNumbers++;
        }

  }

  int newNums[individualNumbers];


That's the only good code I have so far. All my attempts failed.

Thank you.
Last edited on
That's the only good code I have so far.

Sorry, but no. C++ does not support variable length arrays (VLA). Statically allocated array's size has to be known when you compile the binary.

Therefore, the int newNums[individualNumbers]; is not legal.


There are at least three approaches.

* Have a fixed-size array that is large enough and an integer that shows how many elements of the array you actually do use.

* Allocate array dynamically. The size of those arrays does not need to be known before you run the program. However, management of dynamic memory manually is something you don't want to do unless you have to. (You have to understand/learn it at some point.)

* Use of C++ Standard Library containers. The manage dynamic memory on your behalf. Algorithms too.
For example: http://www.cplusplus.com/reference/algorithm/copy_if/


That said,
1
2
for ( int i = 0; i < y.length(); i++ ){
        if ( num[i] != 0 ){

Who are these y and num and what is their relationship?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <valarray>
using namespace std;

template<typename T> ostream &operator << ( ostream &out, const valarray<T> &V )
{
   for ( T e : V ) out << e << " ";
   return out;
}

int main()
{
   valarray<int> num = { 1, 0, 4, 0, 0, 5 };
   valarray<int> newNums = num[num != 0];
   cout << "Original: " << num     << '\n';
   cout << "Filtered: " << newNums << '\n';
}


Original: 1 0 4 0 0 5 
Filtered: 1 4 5 
Last edited on
>> keskiverto

Hey, thanks for the reply. I try to get away from technology as many weekends as I can, so this is my first chance to respond.

It's going to be a program that takes a string with some consecutive letters....
hheeellloo

and print out...

h2e3...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <string>

using namespace std;

int countLet(string p, int q){ // A function to count consecutive identical letters
    int x = 1; // starts at one to accommodate it not counting the last in the consec order
    while (p[q] == p[q+1]){
        x++;
        q++;
        
    }
    return x;
}

int main(){
    int tot = 1;  // currently unused
    
    char x; //this will be an if check later. Currently unused.
    string y; // y is the original string entered. e.g. hhelllooo!!
    
    cin >> x;
    cin.ignore();
    cin >> y;
    
    int num[y.length()] {0}; // num is an array initialized with zeroes
    int individualNumbers = 0;
    
    for (int i = 0; i < y.length(); i++){

        if (y[i] != y[i-1]){ // this if calls the function on just the different letters
        num[i] = countLet(y, i); // then sticks them into the num array
        } // the plan is to cout the letter then it's corresponding number of appearances
  
    }

    for (int i = 0; i < y.length(); i++){

        if (num[i] != 0){
            individualNumbers++;
        }


    }

    int newNums[individualNumbers];
    
}


**This is self learning challenge, not homework or anything like that**
Last edited on
>> last chance

Thank you kindly.
You had VLA already on line 26.

How about: http://www.cplusplus.com/reference/string/string/find_first_not_of/

1
2
3
4
5
6
7
8
9
10
11
12
13
  std::string word;
  if ( std::cin >> word )
  {
    size_t pos = 0;
    size_t next = word.find_first_not_of( word[pos], pos );
    while ( next != std::string::npos )
    {
      std::cout << word[pos] << next - pos;
      pos = next;
      next = word.find_first_not_of( word[pos], pos );
    }
    std::cout << word[pos] << word.size() - pos << '\n';
  }

Notice that there are no arrays (except the 'word' that is a std::string).
>> keskiverto

Thanks for that documentation about dynamic arrays. I went ahead and decided to push myself and try to solve it using dynamic arrays. I was successful.

I'm not saying it is the cleanest solution, but it met the challenge's criteria and passed all tests.

I'll post how I did it, not only on the off chance there are future https://open.kattis.com users or beginners with the same question, but also in hopes that someone more seasoned than me could point out things like potential problems, sketchy code, better ways, etc. since this is long forgotten ground for me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
#include <string>

using namespace std;

int countLet(string p, int q){  // takes in the entire string plus the iteration of the loop

    int x = 1; // Can't start at 0 because no repeats is still a count of 1
   
    while (p[q] == p[q+1]){ 
        x++;
        q++;

    }
   
    return x;

    
}

void decode(char r, char s){ // passes in the string to decode char by char, plus the number as a char

    string xx(1, s); // converts char to string first
    int x = stoi(xx); // then string to int. Because I don't know a better way

    for (int i = 0; i < x; i++){ // a loop to print H4 as HHHH
        cout << r;
    }


}

int main(){

    char x; // indicator of E for encode or D for decode
    string y; // e.g. HHHeellooo!! or H3e2l2o3!2

    cin >> x; 
    cin.ignore(); 
    cin >> y;

    int num[100] {0};  // 100 is the max the string can be
    int counts[100] {0}; // initialized with zeroes to do an easy check to grab anything not zero

    if (x == 'E'){

        num[0] = countLet(y, 0); // I had to call the function on element at zero outside the loop

        for (int i = 1; i < y.length(); i++){ // adjusted the bounds accordingly

            if (y[i] != y[i-1]){ // if a consecutive char is found, it calls the function to count occurences
                num[i] = countLet(y, i);
            }

        }
        
        int tot = 1;
        int *totarr; // dynamic array
        
        for (int i = 1; i < y.length(); i++){

            if (num[i] != 0){
                counts[i]= num[i]; // the array isn't exactly necessary here, but it helped me organize
                tot++;            // in my mind. tot is accumulated to set the bound of dynamic array
            }

        }

        int place = 1; // the place holder for where to stick the elements into the dynamic array
        totarr = new int[tot];
        totarr[0] = num[0]; // again, I found it less troublesome to go ahead and set the 0th element
        
        for (int i = 1; i < y.length(); i++){
            if (counts[i] != 0){
                totarr[place] = counts[i]; // fills dynamic array with all the counts in order
                place++;
            }
        }
        
        int splace = 1; // this block of code does the same thing, but condenses the consec chars to a single char
        char *indiv;
        indiv = new char[place];
        indiv[0] = y[0];
        
        for(int i = 1; i < y.length(); i++){
            if (y[i] != y[i - 1]){
                indiv[splace] = y[i];
                splace++;
            }
        }



        for (int i = 0; i < tot; i++){  // couts them in order
            cout << indiv[i] << totarr[i];
        }


    } // end of encoding

    if (x == 'D'){ // the decoding was much simpler after getting encoding down

        for (int i = 0; i < y.length(); i++){ //input can only be either a letter
            if (isalpha(y[i])){
                decode(y[i], y[i+1]);
            }
            if (ispunct(y[i])){ // or a punctuation character followed by number
                decode(y[i], y[i+1]);
            }
        }


    }

}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

string encode( const string &str )
{
   if ( str.empty() ) return "";
   int p = str.find_first_not_of( str[0] );   if ( p == string::npos ) p = str.size();
   return str[0] + to_string( p ) + ( p < str.size() ? encode( str.substr( p ) ) : "" );
}


string decode( const string &str )
{
   if ( str.empty() ) return "";
   int p = 1;
   while( p < str.size() && isdigit( str[p] ) ) p++;
   return string( stoi( str.substr( 1, p - 1 ) ), str[0] ) + ( p < str.size() ? decode( str.substr( p ) ) : "" );
}


int main()
{
   string test = "hheeellllllllllllo";
   string encoded = encode( test );
   string decoded = decode( encoded );
   cout << test << '\n' << encoded << '\n' << decoded << '\n';
}


hheeellllllllllllo
h2e3l12o1
hheeellllllllllllo


Recursion! Nice! And is that tertiary code too by chance?
Recursion was going to be my first attempt, but I didn't quite know the right way to stop it going to infinity.

I can follow along with your decode function, but not your encode. Will you break it down? How does it move past str[0]?

Thank you.
Yes, it's recursion.

jjordan33 wrote:
is that tertiary code too by chance?

I think it's actually called the "conditional operator" (and it's the one and only "ternary" operator that I know in c++).

For encode: int p = str.find_first_not_of( str[0] );
looks for the first item that isn't equal to the first character, str[0]. There are two possibilities - it doesn't find one (in which case if ( p == string::npos ) p = str.size(); forces it to be the length of the string), or p is the start of the next distinct character. Either way, p will end up being the number of repeats of the character.

str[0] + to_string( p ) then gives the letter and the number of times it occurs.

p < str.size() ? determines if there are any more characters left, and if so recurses from p characters on (encode( str.substr( p ) )); if there aren't any characters left it just stops the recursion by adding an empty string instead.


Actually, I thought decode was harder (because there may be more than one digit after the letter - "12" in the example). However, @Keskiverto explains most of it below.
Last edited on
1
2
int p = 1;
while( p < str.size() && isdigit( str[p] ) ) p++;

The 'p' starts from one past str[0].
h2e
 p

After the loop the p is at the next character, or past the end.
h2e
  p
str.substr( 1, p - 1 ) is the string that contains only digits:
2
1
2
3
4
string digits = str.substr( 1, p - 1 );
int count = stoi( digits );
char value = str[0];
string repeat( count, value ); // ( 2, 'h' ) 

String contructor that creates count long string and initializes each character with value.
The fill constructor: http://www.cplusplus.com/reference/string/string/string/
Okay, so it chips away at the string from the beginning by removing length of p, and stops when it can't find anymore repeats.

Oh, about it being harder than you thought, it definitely could have been, but one of the conditions of the problem stated that the repeat, r, was 0 < r <= 9.

Thanks yall.
Topic archived. No new replies allowed.