-1

I am working on some code for a class that requires me to output duplicates in a string. This string can have any ascii character but the output needs to show only the repeated character and the total number of times it repeats.

Here are some sample inputs and outputs

mom, m:2

taco, No duplicates

good job, o:3

tacocat, t:2 c:2 a:2

My code works for all but the last test case, the t:2 and a:2 appears twice, Now I have come to the conclusion that I need to store duplicated characters somewhere and run a check on that list to see if that duplicate has already been printed so I tried using a vector.

My method is to push the character into the vector as the duplicates are printed and if a character is already in the vector then it is skipped in the printing. But I have not been able to find a way to this. I tried to use the find() from #include<algorithm> but got a syntax error that I am unable to fix. Is there a function that I can apply for this? Or am I going about this in a bad way?

I found the implementation of find() here & I looked here but they don't match and it breaks my code completely when I try to apply it.

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
vector <char> alreadyprintedcharacters;
void findrepeats(string const&);
int main()
{
    string input;
    cout << "Enter the input : ";
    getline(cin, input);
    findrepeats(input);
    return 0;
}
void findrepeats(string const &in)
{
    int trackerOfDuplicates = 0; 
    int asciiArray[256];
    char ch;
    int charconv;
    for (int i = 0; i < 256; i++) // creates my refference array for the comparison and sets all the values equal to zero
        asciiArray[i] = 0;
    for (unsigned int i = 0; i < in.length(); i++)
    {
        ch = in[i];
        charconv = static_cast<int>(ch);
        if (asciiArray[charconv] == 0)
        {
            asciiArray[charconv] = 1;
        }
        else if (asciiArray[charconv] > 0)
        {
            asciiArray[charconv] = asciiArray[charconv]++;
        }
        
    }
    bool trip = false;
    for (unsigned int i = 0; i < in.length(); i++)
    {
        char static alreadyprinted;
        char ch = in[i];
        
        if ((asciiArray[ch] > 1) && (ch != alreadyprinted) && (find(alreadyprintedcharacters.begin(), alreadyprintedcharacters.end(), ch)!= alreadyprintedcharacters.end()))// change reflected HERE
        {
            cout << in[i] << " : " << asciiArray[ch] << endl;//???? maybe a nested loop
            trip = true;
            alreadyprinted = ch;
            alreadyprintedcharacters.push_back(alreadyprinted);
        }
        
            
        

    }
    if (trip == false)
        cout << "No repeated characters were found.\n";
}
Community
  • 1
  • 1
Callat
  • 2,928
  • 5
  • 30
  • 47
  • Does the letter sequence "eof" appear anywhere in your code? – Kerrek SB Apr 17 '16 at 18:03
  • No, eof means end of file and here I'm not using a file. It takes user input. – Callat Apr 17 '16 at 18:06
  • 1
    @Hikari You know that this is a 4 or 5 line program using `std::map`? – PaulMcKenzie Apr 17 '16 at 18:08
  • @PaulMcKenzie I read in a few places that it is easy to use maps but I have no idea what those are. Plus this is for a class and I can't use stuff we haven't covered in lecture. – Callat Apr 17 '16 at 18:13
  • If anyone feels the need to downvote me please explain why. I have a legitimate question and if it is unclear I am more than willing to change it so that it is clear. – Callat Apr 17 '16 at 18:24
  • 1
    @Hikari The map will keep a total of each character encountered by just incrementing the count for that character. See [this example](http://ideone.com/luov6s). But even so, your code seems to be doing a mountain of work for something that should be simple. You see a character, you bump up the count of it in your array. At the same time, if the incremented value is > 1, then you know you have at least one dup. All of this "already printed" stuff -- what's the purpose of it? After you've processed the string, just go one by one through your array, and if the value is > 1, print it. – PaulMcKenzie Apr 17 '16 at 18:27
  • @PaulMcKenzie this... IS... AWESOME!!! but I've never seen a for_reach loop or a map before so it took a bit of googling to understand. This looks way more efficient but I can't use concepts we haven't covered. And we don't learn maps until the next level class. So I can't use it. – Callat Apr 17 '16 at 18:33

7 Answers7

2

Your code works fine for me (gives the correct output for tacocat) if you fix the error related to std::find:

std::find doesn't return a bool, it returns an iterator (in your case, a std::vector<char>::iterator). If you want to check if std::find found something, you should compare it to alreadyprintedcharacters.end(), because that's what std::find returns if it didn't find something.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • I tried that and i still have the wrong output for all of my test cases. Is there something wrong with how I have find() within the if()? Please give it a look and let me know. – Callat Apr 17 '16 at 18:25
  • NVM! I GOT IT!!! You pointed me in the right direction! I needed to add this if ((asciiArray[ch] > 1) && (ch != alreadyprinted) && (find(alreadyprintedcharacters.begin(), alreadyprintedcharacters.end(), ch)== alreadyprintedcharacters.end())) all that changed was the != to a ==!!! THANK YOU SO MUCH! – Callat Apr 17 '16 at 18:37
2

You can create an integer array of 256 and initialize it to 0 at first. Then loop over characters in the string and increment each index that corresponds to that letter. In the end, you can print out letters that have values greater than 1. Just change your findrepeats function to the following:

void findrepeats(string const &in)
{
    int asciiArray[256];
    char ch;
    int charconv;
    bool foundAny = false;
    for (int i = 0; i < 256; i++) asciiArray[i] = 0;
    for (unsigned int i = 0; i < in.length(); i++)
    {
        ch = in[i];
        charconv = static_cast<int>(ch);
        asciiArray[charconv]++;
    }
    for (unsigned int i = 0; i < 256; i++)
    {
        char static alreadyprinted;

        if (asciiArray[i] > 1)
        {
            foundAny = true;
            cout << static_cast<char>(i) << " : " << asciiArray[i] << endl;
        }
    }
    if (!foundAny)
        cout << "No repeated characters were found.\n";
}
Ferit Buyukkececi
  • 2,665
  • 2
  • 20
  • 23
1

You have to make following changes in your code

  1. change the loop body where you are updating the reference array for the comparison and sets all the values like this:

    //your code
    else if (asciiArray[charconv] > 0)
    {
        asciiArray[charconv] = asciiArray[charconv]++;
    }
    

    in the above code the value of asciiArray[charconv] doesn't change because it is a post increment asciiArray[charconv]++; , either change it to a pre increment ++asciiArray[charconv]; or write asciiArray[charconv] = asciiArray[charconv]+1; Here is a link to this why it doesn't increment.

    Also you can change the loop like this,more simplified:

    for (unsigned int i = 0; i < in.length(); i++)
    {
        ch = in[i];
        charconv = static_cast<int>(ch);
        asciiArray[charconv]++;
    }
    
  2. change the type of found to std::vector<char>::iterator coz find returns an iterator to the first element in the range that compares equal to val & if no elements match, the function returns last.

    std::vector<char>::iterator found = find(alreadyprintedcharacters.begin(), alreadyprintedcharacters.end(), ch);
    

    Then your condition should be like

    if((asciiArray[ch] > 1) && (ch!=alreadyprinted) && (found == alreadyprintedcharacters.end()))
    
Community
  • 1
  • 1
Rajeev Singh
  • 3,292
  • 2
  • 19
  • 30
  • Change 1 is great for optimization! but my problem was with change 2 and your right! I got it to work a bit differently though by replacing found with plugging the function directly into the if statement. I don't think the first change makes the code function differently or not. – Callat Apr 17 '16 at 18:40
  • @Hikari I added the reason for the change 1 , see the updated answer – Rajeev Singh Apr 17 '16 at 18:50
  • I see. But in this case since it is being set equal to itself. asciiArray[charconv] = asciiArray[charconv]++; it still does the increment but the assignment is an unneccessary one. And if this was setting something else it would create an error. Right? – Callat Apr 17 '16 at 19:26
  • Let take `i=i++;` and i=5. 1. i++ is evaluated.Since it is post incrementation ,first the value will be used,and then incremented. 5 will be used 2.Now i increments and it becomes 6,but remember 5 will be used with in the whole expression 3.Now assignment operator is executed.i will be assigned the value of i++.Since its post incremented,the original value is assigned not the incremental value – Rajeev Singh Apr 17 '16 at 19:56
1

I don't quite get why you need all of that code (given you stated you can't use std::map).

You declared an array of 256 and set each item to 0, which is OK:

   for (int i = 0; i < 256; i++) 
      asciiArray[i] = 0;

Now the next step should be simple -- just go through the string, one character at a time, and increment the associated value in your array. You seem to start out this way, then go off on a tangent doing other things:

 for (unsigned int i = 0; i < in.length(); i++)
    {
      ch = in[i];  // ok
      asciiArray[ch]++;

We can set a boolean to true if we discover that the character count we just incremented is > 1:

bool dup = false;
for (unsigned int i = 0; i < in.length(); i++)
{
  ch = in[i];  // ok
  asciiArray[ch]++;
  if ( asciiArray[ch] > 1 )
    dup = true;
}

That is the entire loop to preprocess the string. Then you need a loop after this to print out the results.

As to printing, just go through your array only if there are duplicates, and you know this by just inspecting the dup value. If the array's value at character i is > 1, you print the information for that character, if not, skip to the next one.

I won't show the code for the last step, since this is homework.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • I think it's just the difference in experience like for the second code block. You saw that asciiArray[ch] needs to increment so you just did asciiArray[ch]++. When I saw that I tried asciiArray[ch++] which screwed up my index and led me to believe that I needed the if else statements. Until Rajeev posted above I had no idea that it could be done without them. For the printing I ran into an issue keeping up with the indexes of both things and what to do when a duplicate repeats itself. I'm sure other can come up with better ways but that's a nod to all of your experience. – Callat Apr 17 '16 at 19:33
1

Just met similar question last week, here is what I did, maybe not a best solution, but it did work well.

string str("aer08%&#&%$$gfdslh6FAKSFH");

vector<char> check;
vector<int> counter;
//subscript is the bridge between charcheck and count. counter[sbuscript] store the times that check[subscript] appeared
int subscript = 0;
bool charisincheck = false;


for (const auto cstr : str) //read every char in string
{
    subscript = 0;
    charisincheck = false;

    for (const auto ccheck : check) // read every element in charcheck
    {
        if (cstr == ccheck)//check if the char get from the string had already existed in charcheck
        {
            charisincheck = true; //if exist, break the for loop
            break;
        }
        subscript++;
    }

    if (charisincheck == true) //if the char in string, then the count +1
    {
        counter[subscript] += 1;
    }
    else //if not, add the new char to check, and also add a counter for this new char
    {
        check.push_back(cstr);
        counter.push_back(1);
    }

}

for (decltype(counter.size()) i = 0; i != counter.size(); i++)
{
    cout << check[i] << ":" << counter[i] << endl;
}met
Dirty Oleg
  • 113
  • 1
  • 8
0
import java.util.*;
class dublicate{
 public static void main(String arg[]){
Scanner sc =new Scanner(System.in);
String str=sc.nextLine();
int d[]=new int[256];
int count=0;
for(int i=0;i<256;i++){
 d[i]=0;
}
 for(int i=0;i<str.length();i++){
if(d[str.charAt(i)]==0)
for(int j=i+1;j<str.length();j++){
if(str.charAt(i)==str.charAt(j)){
d[str.charAt(i)]++; 
}
}
}
 for(char i=0;i<256;i++){
 if(d[i]>0)
System.out.println(i+" :="+(d[i]+1));
}
}
}
0
//here simple code for duplicate characters in a string in C++

#include<iostream.h>
#include<conio.h>
#include<string.h>
void main(){
clrscr();

char str[100];
cin>>str;
int d[256];
int count=0;

for(int k=0;k<256;k++){
d[k]=0;
}


  for(int i=0;i<strlen(str);i++){
if(d[str[i]]==0)
for(int j=i+1;j<strlen(str);j++){
if(str[i]==str[j]){
d[str[i]]++;
}
}
}

for(int c=0;c<256;c++){
if(d[c]>0)
cout<<(char)c<<" :="<<(d[c]+1)<<"\n";
}
getch();
}