I'm currently working on a small program where I will count the amount of times a certain word is mentioned in a text. But I only want to count for the word when the previous element is a 10 digit number.
So what I'm trying is do is that I will check if the previous element of the iterator consist of a 10 digit number. But I don't know how to iterate to the previous element from the iterator.
QString input = ui->listinput->toPlainText();
QStringList inputlist = input.split(QRegExp("[\s\n\r " "]+"));
unsigned int boxCount(0);
for(QStringList::iterator it(inputlist.begin()); it != inputlist.end(); ++it){
if(!QString::compare(*it,box)) ++boxCount;
}
So I want the if statement to be something like this:
if(!QString::compare(*it,box) && *prev_it == 10 digits) ++boxCount;
Any help will be appreciated. Thanks!
You can obtain the previous iterator by doing:
if (it != inputlist.begin()) {
prev_it = it - 1
}
You will have to make an exception for the first element, since it has no previous element. Either check the range (like above) or start your for loop one element past the first (note the '+ 1'):
for (QStringList::iterator it(inputlist.begin() + 1); it != inputlist.end(); ++it) {
...
}
In the latter case, you must be sure that your list contains at least one element.
If you then want to check if the number is 10-digit (assuming decimal and integer) you can try the following:
bool ok = false;
long num = prev_it->toLong(&ok);
if (ok && num >= 1000000000) {
// do something
}
Note: I used the long type because I do not know the range of your numbers, but they seemed big.
Related
Expected output is "ca" but I'm getting "aca". I have dry ran it, but do not understood why it is doing so. Please, can anyone help me in solving this?
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a = "abbaca";
int i = 0;
while(i < a.size()){
if(a[i] == a[i+1]){
a.erase(i, i+1);
i = 0;
}
else{
i++;
}
}
cout << a;
return 0;
}
a.erase(i, i+1) is wrong.
The string::erase() method takes a starting index and a count, not a pair of indexes denoting a range, as you are thinking.
When removing the duplicate bs, i is 1, and you erase i+1=2 chars, thus "abbaca" becomes "aaca", which is correct. But then, the loop starts over, and when removing the duplicate as, i is 0, so you erase i+1=1 char, thus "aaca" becomes "aca", which is wrong.
You want to remove exact 2 chars each time, so use a.erase(i, 2) instead.
Online Demo
The function 'erase()' erases a part of the string content, shortening the length of the string.The second parameter in the erase function is the count, it means how many characters you want it to remove. If you want 'ca' as expected output you should mention 2 as count of characters to be removed. In the first case it becomes 2 so bb is removed but for 'aa' the count becomes as 1 so 'aca' is the output.
Below is the code for output 'ca', change this erase statement as shown:
if(a[i]==a[i+1]){
a.erase(i,2);
i=0;
}
keep the rest as same
I want to write a program that get the numbers with this rule :
every number be greater or smaller than the numbers before and after itself. like : 3 1 4 2 6 0 8 3 5 16
Whenever this rule was violated, stop getting number.
int a, b, c;
bool flag = true;
cin >> a;
while (flag)
{
cin >> b;
cin >> c;
if ((b < a && b < c) || (b > a && b > c))
{
flag = true;
a = c;
}
else
{
break;
}
}
My code works for some inputs but for this inputs : 3 1 4 6
When i enter 6 the program must be stop, but it continue to input next number. What should i do to fix it?
The solution to this problems involves a lot of logical evaluations. So, we need many boolean expressions and if statements.
One key to the solution, is to keep track of 2 values:
The current read value
The preivously read, old value
We can always compare those values and then make descisions. Problem is that we do not have an "previous" value in the beginning. So, we need to do a special treatment and first read a value from the user, store this as prvious value, and then always read a current value in a loop.
At the end of the loop, we will assign the current value to the "previuosValue". Then in the next loop run, we always need to read only the current value from the user.
Ant those 2 values, we can compare in a while loop.
We compare the current value with the previous value, and, depending of the outcome, define a "direction" flag for further comparisons.
This we do after having read the 2nd number. After that the direction is always defined and will never change.
Example, if the current value is bigger than the previous value, then, in the next loop, the next value must be smaller. And vice versa.
Example:
First value: 2
2nd value: 6
The second value is bigger than the first value. So, for next values we expect
small --> big --> small --> big --> small --> big --> . . .
and so on. This will never change.
Same is valid vice versa.
First value: 9
2nd value: 1
The second value is smaller than the first value. So, for next values we expect
big --> small --> big --> small --> big --> small --> big --> . . .
The direction flag will always be inverted after having processed the "next" number.
We can then evaluate the stop condition in the next loop run. Does the comparision result to a value, to a direction, that we expect?
If not, or if the values are equal, then we stop the input.
Of course, we will not do this evaluation in the first loop, because then, we have always a valid pair and calculate the direction afterwards.
So, you see. We always need only 2 variables.
There are many possible implementations, as always. Please see the below as an example for a solution:
#include <iostream>
int main() {
// Read initial previous number (The first number)
if (int previousNumber{}; std::cin >> previousNumber) {
// Flag that indicates, if we should continue reading new numbers or not
bool continueToRead{ true };
// First number needs special treatment, there is no other number
bool firstCheck{ true };
// The "direction" of the comparison
bool nextNumberMustBeSmaller{false};
// Read numbers in a loop
while (continueToRead) {
// Read current (next) number
if (int currentNumber{}; std::cin >> currentNumber) {
// After heaving read the first value in the loop, we can detect the direction
if (firstCheck) {
// Get the "direction" of the comparison for the next numbers
// If the number is bigger than last number
if (currentNumber > previousNumber)
// Then next value muste be smaller
nextNumberMustBeSmaller = true;
// If this number is smaller
else if (currentNumber < previousNumber)
// then next number must be bigger
nextNumberMustBeSmaller = false;
else
continueToRead = false;
// First check has been done
firstCheck = false;
}
else {
// Find out the stop condition
if (
// Direction is smaller but number is bigger or
(nextNumberMustBeSmaller and (currentNumber > previousNumber)) ||
// Direction is bigger but number is smaller or
(not nextNumberMustBeSmaller and (currentNumber < previousNumber)) ||
// Or numbers are equal
(currentNumber == previousNumber)) {
// Then: Stop reading values
continueToRead = false;
}
nextNumberMustBeSmaller = not nextNumberMustBeSmaller;
}
// Remember the last value. So, for the next loop rund, the current value will become the previous one
previousNumber = currentNumber;
}
else {
std::cerr << "\n\nInvalid input\n\n";
continueToRead = false;
}
}
}
else std::cerr << "\n\nInvalid input\n\n";
return 0;
}
To be compiled with C++17 enabled.
Here are some observations if we take the task as given in your question, but I think you may have misunderstood the task in one way or another.
every number be greater or smaller than the numbers before and after itself
greater or smaller means not equal.
you can't check the next number. You don't even know if there is a next number, so you can only check against the previous number
The final condition then becomes "stop if current and last number are equal"
In code this could look like this:
int a, b;
cin >> a;
while (cin >> b && a != b)
{
a = b; // current number becomes the last number
}
Note that I removed flag, because it was never set to false. The break will be enough. And I moved the cin >> b into the loop condition to validate the input. Then it turned out that we can merge the if-block into the loop condition as well.
Update:
So it turns out there were two issues:
The first is that I checked the [k-1] index before I checked k == 0. This was a crash, although mostly fixable, and not the primary issue I posted about.
The primary issue is that the code seems to execute only after I press ctrl+z. Not sure why that would be.
Original:
So, learning from Stroustrup's text in C++ programming, I got to an example on vectors and tried implementing it myself. The gist is that the program user enters a bunch of words, and the program alphabetizes them, and then prints them without repeats. I managed to get working code using a for statement, but one of my initial attempts confuses me as to why this one doesn't work.
To be clear, I'm not asking to improve this code. I already have better, working code. I'm wondering here why the code below doesn't work.
The "error" I get is that the code compiles and runs fine, but when I input words, nothing happens and I'm prompted to input more.
I'm certain there's an obvious mistake, but I've been looking everywhere for the last 8 hours (no exaggeration) just devoted to finding the error on my own. But I can't.
int main() {
vector<string> warray; string wentry; int k = 0;
cout << "Enter words and I'll alphabetize and delete repeats:\n\n";
while (cin >> wentry) warray.push_back(wentry);
sort(warray.begin(), warray.end());
while (k < warray.size()) {
if (warray[k - 1] != warray[k] || k == 0) cout << warray[k] << "\n";
++k;
}
}
My reasoning for why this should work is this: I initialize my array of words, my word entry per input, and a variable to index word output.
Then I have a while statement so that every input is stacked at the end of the array.
Then I sort my array.
Then I use my index which starts at 0 to output the 0th item of the array.
Then so long as there are words in the array not yet reached by the index, the index will check that the word is not a repeat of the prior index position, and then print if not.
No matter what whappens, the index is incremented by one, and the check begins again.
Words are printed until the index runs through and checks all the words in the array.
Then we wait for new entries, although this gets kind of screwy with the above code, since the sorting is done before the checking. This is explicitly not my concern, however. I only intend for this to work once.
To end the cycle of input you need to insert EOF character which is ctrl+d. However, there are other problems in your code. You have k = 0 to start with so the moment you will try warray[k - 1] your code will crash.
At the point where you take
warray[k - 1]
for the first time, k is zero, so you want to get the warray value at index -1, which is not necessarily defined in memory (and even if, I wouldn't do this anyway). So as it compiles, I guess the address is defined in your case by accident.
I would try simply reversing the OR combination in your if-condition:
if (k == 0 || warray[k - 1] != warray[k])
thus for the first iteration (k == 0) it won't check the second condition because the first condition is then already fulfilled.
Does it work then?
You're stuck in the while loop because you don't have a way of breaking out of it. That being said, you can use Ctrl + d (or use Ctrl + z if executing on windows in the command prompt) to break out of the loop and continue executing the code.
As for while loop at the bottom which prints out the sorted vector of values, your program is going to crash as user902384 suggested because your program will first check for warray[k - 1].
Ideally, you want to change the last part of your program to:
while (k < warray.size())
{
if (k == 0 || warray[k - 1] != warray[k])
cout << warray[k] << "\n";
++k;
}
This way, the k == 0 check passes and your program will skip checking warray[k - 1] != warray[k] (which would equal warray[-1] != warray[0] when k=0).
You just needed to reverse:
if (warray[k - 1] != warray[k] || k == 0)
to
if (k == 0 || warray[k - 1] != warray[k] )
for terminating this condition if k = 0.
An alternative.
Although it can termed as a bit off topic, considering you want to work with std::vector<>, but std::set<> is an excellent container which satisfies your current two conditions:
Sort the strings in alphabetical order.
Delete all the repetitions.
Include <set> in your .cpp file, and create a set object, insert all the std::string and iterate through the set to get your ordered, duplicate-free strings!
The code:
int main() {
//Define a set container.
set<string> s;
//A temporary string variable.
string temp;
//Inserting strings into the set.
while (cin >> temp) s.insert(temp);
//Create a set<int> iterator.
set<string>::iterator it;
//Scanning the set
for(it = s.begin(); it != s.end(); ++it)
{
//To access the element pointed by the iterator,
//use *it.
cout<<*it<<endl;
}
return 0;
}
I just recommended this container, because you will study set in Stroustrup's text, and it is very easy and convenient instead of laboring over a vector.
This question already has answers here:
Given a word and a text, we need to return the occurrences of anagrams
(6 answers)
Closed 9 years ago.
For eg. word is for and the text is forxxorfxdofr, anagrams of for will be ofr, orf, fro, etc. So the answer would be 3 for this particular example.
Here is what I came up with.
#include<iostream>
#include<cstring>
using namespace std;
int countAnagram (char *pattern, char *text)
{
int patternLength = strlen(pattern);
int textLength = strlen(text);
int dp1[256] = {0}, dp2[256] = {0}, i, j;
for (i = 0; i < patternLength; i++)
{
dp1[pattern[i]]++;
dp2[text[i]]++;
}
int found = 0, temp = 0;
for (i = 0; i < 256; i++)
{
if (dp1[i]!=dp2[i])
{
temp = 1;
break;
}
}
if (temp == 0)
found++;
for (i = 0; i < textLength - patternLength; i++)
{
temp = 0;
dp2[text[i]]--;
dp2[text[i+patternLength]]++;
for (j = 0; j < 256; j++)
{
if (dp1[j]!=dp2[j])
{
temp = 1;
break;
}
}
if (temp == 0)
found++;
}
return found;
}
int main()
{
char pattern[] = "for";
char text[] = "ofrghofrof";
cout << countAnagram(pattern, text);
}
Does there exist a faster algorithm for the said problem?
Most of the time will be spent searching, so to make the algorithm more time efficient, the objective is to reduce the quantities of searches or optimize the search.
Method 1: A table of search starting positions.
Create a vector of lists, one vector slot for each letter of the alphabet. This can be space-optimized later.
Each slot will contain a list of indices into the text.
Example text: forxxorfxdofr
Slot List
'f' 0 --> 7 --> 11
'o' 1 --> 5 --> 10
'r' 2 --> 6 --> 12
For each word, look up the letter in the vector to get a list of indexes into the text. For each index in the list, compare the text string position from the list item to the word.
So with the above table and the word "ofr", the first compare occurs at index 1, second compare at index 5 and last compare at index 10.
You could eliminate near-end of text indices where (index + word length > text length).
You can use the commutativity of multiplication, along with uniqueness of primal decomposition. This relies on my previous answer here
Create a mapping from each character into a list of prime numbers (as small as possible). For e.g. a-->2, b-->3, c-->5, etc.. This can be kept in a simple array.
Now, convert the given word into the multiplication of the primes matching each of its characters. This results will be equal to a similar multiplication of any anagram of that word.
Now sweep over the array, and at any given step, maintain the multiplication of the primes matching the last L characters (where L is the length of your word). So every time you advance you do
mul = mul * char2prime(text[i]) / char2prime(text[i-L])
Whenever this multiplication equals that of your word - increment the overall counter, and you're done
Note that this method would work well on short words, but the primes multiplication can overflow a 64b var pretty fast (by ~9-10 letters), so you'll have to use a large number math library to support longer words.
This algorithm is reasonably efficient if the pattern to be anagrammed is so short that the best way to search it is to simply scan it. To allow longer patterns, the scans represented here by the 'for jj' and 'for mm' loops could be replaced by more sophisticated search techniques.
// sLine -- string to be searched
// sWord -- pattern to be anagrammed
// (in this pseudo-language, the index of the first character in a string is 0)
// iAnagrams -- count of anagrams found
iLineLim = length(sLine)-1
iWordLim = length(sWord)-1
// we need a 'deleted' marker char that will never appear in the input strings
chNil = chr(0)
iAnagrams = 0 // well we haven't found any yet have we
// examine every posn in sLine where an anagram could possibly start
for ii from 0 to iLineLim-iWordLim do {
chK = sLine[ii]
// does the char at this position in sLine also appear in sWord
for jj from 0 to iWordLim do {
if sWord[jj]=chK then {
// yes -- we have a candidate starting posn in sLine
// is there an anagram of sWord at this position in sLine
sCopy = sWord // make a temp copy that we will delete one char at a time
sCopy[jj] = chNil // delete the char we already found in sLine
// the rest of the anagram would have to be in the next iWordLim positions
for kk from ii+1 to ii+iWordLim do {
chK = sLine[kk]
cc = false
for mm from 0 to iWordLim do { // look for anagram char
if sCopy[mm]=chK then { // found one
cc = true
sCopy[mm] = chNil // delete it from copy
break // out of 'for mm'
}
}
if not cc then break // out of 'for kk' -- no anagram char here
}
if cc then { iAnagrams = iAnagrams+1 }
break // out of 'for jj'
}
}
}
-Al.
I have the following piece of code which helps me to write a bunch of values into a comma separated file format. My problem is, that I do not want a comma after the last element written to normcsv. How can I use beg in an If clause of the kind:
if(beg == penultimate element)
then.... bla bla...
Everything I tried out ended up with the iterator being mad invalid
ReadLine.erase(0,17);
int offsets[] = {8,8,8,8,8,8};
boost::offset_separator f(offsets, offsets+6);
boost::tokenizer<boost::offset_separator> RVBEARline(ReadLine,f);
boost::tokenizer<boost::offset_separator>::iterator beg;
for( beg=RVBEARline.begin(); beg!=RVBEARline.end();++beg )
{
copy=*beg;
boost::trim(copy);
if(copy.compare(0,1,".")==0)
{
copy.insert(0,"0");
}
normcsv << copy <<",";
}
Instead of printing the comma after the element except during the last iteration, print it before the element except during the first iteration. For that, you can use if(beg != RVBEARline.begin()).
An alternative to ruakh's "first plus rest" approach, you can do with one less local variable by using a loop-and-a-half construct:
{
auto it = x.begin(), end = x.end();
if (it != end)
{
for ( ; ; )
{
process(*it);
if (++it == end) break;
print_delimiter();
}
}
}
Here x.begin() and x.end() are only called once. There is one mandatory comparison per loop round, the minimum possible. The check for emptiness is hoisted outside.
Couldn't you just always remove the last character since you know it will be an extraneous comma?