I'm trying to do a loop for this part:
insert_front(&list,name[0]);
insert_front(&list,name[1]);
insert_front(&list,name[2]);
but, i can't figure out which should be used as a limiter, which should stop the loop for going and how it will change the name[] perimeters.
Here's the whole code:
#include "list.h"
#include "string"
using namespace std;
int main(){
cout<<"What is your name \n";
string name;
getline(cin,name);
Node *list;
list = new_list();
insert_front(&list,name[0]);
insert_front(&list,name[1]);
insert_front(&list,name[2]);
}
print_list(list);
delete_list(&list);
print_list(list);
return 0;
}
Iterator version (C++03):
for (std::string::iterator iter = name.begin(); iter != name.end(); ++iter)
insert_front(&list, *iter);
Foreach version (C++11):
for ( char c : name)
insert_front(&list, c);
Index version (C++03):
for (size_t i = 0; i < name.size(); ++i)
insert_front(&list, name[i]);
Foreach version (C++03 with Boost):
std::for_each(name.begin(), name.end(), boost::bind(insert_front, &list, _1));
I'm not so sure on the C++11 foreach version.
There's probably also a reasonable way to use std::copy or std::transform if your hand-coded list has iterators.
That's not really "the whole code" as you say. What elements does your list store? Looks to be a single character per node. So it appears you are you trying to make a list of characters to represent the person's name in reverse order.
That being the case:
for( size_t i = 0; i < name.length(); i++ ) {
insert_front(&list,name[i]);
}
The Standard Template Library, which strings are part of, provide some nice efficient and safe iterators for dealing with items you might want to loop over.
for(string::iterator iter = name.begin(); iter < name.end(); iter++) {
insert_front(&list, *iter);
}
string::begin shows this same example.
string::begin() returns an object that when dereferenced with operator* gives the value where its at. operator++() increments to the next position. string::end() gives another object after the end of the string so that the operator==() after the operator++() stops the loop.
Now, the important part here is that you aren't using indices. Many STL containers let you copy in values using the iterators. You could even skip the for loop to use an stl list and do something like the following:
std::list list (name.begin(), name.end());
Done. No manual for loop or for_each() call at all. You can even use name.begin() + 1 to skip the first character. See the list constructor for this.
As pointed out in a comment, to achieve the insert_front() reversing effect, this should be:
std::list list (name.rbegin(), name.rend());
string::rebgin() and string::rend() iterate in reverse order. To be simpler, this is coming after the use of string::begin() and string::end() to introduce the reversal separately.
Obviously, you are using a different list and will need some looping to continue using it. But, you might just decide to leave the string as a string and pass the relevant iterators to a print function and avoid using a list at all. This might allow you to make code generic enough to not care whether this is from a string or list.
I think you are trying to do:
for(int i=0; i<name.size(); i++)
{
insert_front(&list,name[i]);
}
And this will store each character of the name in the list.
Related
In other words, what I mean to say is : Is itr+=2 a valid argument in c++ ?, where (itr is an iterator to first element of the set). If so, then the following piece of code should work:
In this piece if code, the code written in /comment section/ functions well, while the code not in comment section do not. Help me out to iterate alternate elements.
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> s;
s.insert(5);
s.insert(7);
s.insert(8);
auto it=s.begin();
cout<<*it<<'\n';
it+=2;
cout<<*it<<'\n';
/*for(auto it=s.begin();it!=s.end();it++)
cout<<*it<<" ";*/
return 0;
}
Is itr+=2 a valid argument in c++?
It depends on the container type. For example, it would be perfectly valid for std::vector or std::array, but not for std::set. Each container, due to its nature, provides different types of iterators. std::set only provides BidirectionalIterator, which do not support jumping over arbitrary number of elements, only incrementation and decrementation.
However, you can use std::advance() from <iterator> library (or just increment the iterator twice). Beware that you must never increment end() iterator, so you need to take it into account in loop condition.
for(auto it=s.begin(); it != s.end() && it != std::prev(s.end()); std::advance(it, 2))
i found many answers for erase an element of vector has a certain character
but i tried to make some of these solutions to erase the element which hasn't that character but dosen't work
for(int k=0; k<temp.size();k++)
{
while(temp[k].find_first_of("xX")!= string::npos)
{
temp.erase(temp.begin()+k);
}
}
variables_print.push_back(temp);
here an example , these code erase the elements have char "xX" but i tried to make it temp[K].find_first_not_of("xX") and doesn't work
also make it temp[K].find_first_of("xX")== string::npos and doesn't work
how to erase the elements haven't x or X characters
You could do it this way:
auto newEnd = std::remove_if(v.begin(), v.end(),
[](const auto& s) { return s.find_first_of("xX") == std::string::npos; });
v.erase(newEnd, v.end());
remove_if moves all elements not matching the condition to front, replacing those that satisfy the it. The condition here is satisfied when the lambda given as the third argument returns true. newEnd is the iterator pointing to the first element after those that are not removed.
For example, if input is this: {"aaa", "bbx", "ccc"}, after call to remove_if the vector looks like this: {"aaa", "ccc", <used to be bbx>}.
The second line removes all elements starting fromnewEnd. So in example above, you end up with {"aaa", "ccc"}.
The condition here is a lambda which returns true for each element that contains neither 'x' nor 'X'.
This is the same condition you tried - and is correct one. Problem with your original code different.
Look at: while(temp[k].find_first_of("xX")!= string::npos). If the string does not contain X, the body of this nested loop will not be executed and nothing gets removed. Also, you could replace the loop with a simple if statement.
There's another problem with the outer loop. You increment k each time, even if you've just removed an element. Consider this example: {"x", "x"}. When incrementing k each time, you will skip the second string and end up with {"x"}.
The corrected code looks would look like this:
for(size_t k=0; k<v.size(); )
{
if(v[k].find_first_of("xX") == std::string::npos)
{
v.erase(v.begin()+k);
}
else
{
++k;
}
}
Compare this with the first version. It's not only shorter, but also leaves much less room for bugs.
As #Bob_ points out in comments, the first version is known as erase-remove idiom. It's a common thing to see in modern C++ (i. e. C++11 and newer), so it's worth getting used to it and using it.
this is my homework:
Write a function to prints all strings with a length of 3. Your
solution must use a for loop with iterators.
void print3(const set & str)
And this is my code:
void print3(const set<string>& str){
string st;
set<string,less<string>>::iterator iter;
for(iter=str.begin();iter!=str.end();++iter)
{st=*iter;
if(st.length()==3) cout<<st<<' ';
}
}
But I think it's not good. Do someone have a better code? Please, help me to improve it.
-I have another question about iterator
string name[]={"halohg","nui","ght","jiunji"};
set<string> nameSet(name,name+4);
set<string>::iterator iter;
iter=name.begin();
How can I access name[2]="ght" by using iterator?
I tried iter+2 but it has some problems. I think I have to use random access iterator but I don't know how to use it.
Please, help me. Thanks a lot!
Some thoughts on improvement:
You can get rid of string st; and just check if (iter->length() == 3).
Another improvement would be to use a const_iterator instead of an iterator, since you aren't modifying any of the items.
Also, adding less<string> as a template parameter is kind of useless, since that's the default compare functor anyway, so it can be removed.
And lastly, it's generally a good idea to declare your locals with minimal scope (so they don't pollute other scopes or introduce unexpected hiding issues), so usually you want to declare your iter in the for.
So it becomes:
for (set<string>::const_iterator iter = str.begin(); iter != str.end(); ++iter) {
if (iter->length() == 3) cout << *iter << ' ';
}
That's about as good as you can get, given your requirements.
As for your second question, set's iterator is not a random access iterator. It's a (constant) Bidirectional Iterator. You can use std::advance if you wanted, though, and do:
std::set<std::string>::iterator iter;
iter = name.begin();
std::advance(iter, 2);
// iter is now pointing to the second element
Just remember that set sorts its elements.
I am new to the C++ language. I have been starting to use vectors, and have noticed that in all of the code I see to iterate though a vector via indices, the first parameter of the for loop is always something based on the vector. In Java I might do something like this with an ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Is there a reason I don't see this in C++? Is it bad practice?
The reason why you don't see such practice is quite subjective and cannot have a definite answer, because I have seen many of the code which uses your mentioned way rather than iterator style code.
Following can be reasons of people not considering vector.size() way of looping:
Being paranoid about calling size() every time in the loop
condition. However either it's a non-issue or it can be trivially
fixed
Preferring std::for_each() over the for loop itself
Later changing the container from std::vector to other one (e.g.
map, list) will also demand the change of the looping mechanism,
because not every container support size() style of looping
C++11 provides a good facility to move through the containers. That is called "range based for loop" (or "enhanced for loop" in Java).
With little code you can traverse through the full (mandatory!) std::vector:
vector<int> vi;
...
for(int i : vi)
cout << "i = " << i << endl;
The cleanest way of iterating through a vector is via iterators:
for (auto it = begin (vector); it != end (vector); ++it) {
it->doSomething ();
}
or (equivalent to the above)
for (auto & element : vector) {
element.doSomething ();
}
Prior to C++0x, you have to replace auto by the iterator type and use member functions instead of global functions begin and end.
This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?
Is there any reason I don't see this in C++? Is it bad practice?
No. It is not a bad practice, but the following approach renders your code certain flexibility.
Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:
std::vector<int>::iterator it = vector.begin();
This is because it makes the code more flexible.
All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.
Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.
The right way to do that is:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
it->doSomething();
}
Where T is the type of the class inside the vector. For example if the class was CActivity, just write CActivity instead of T.
This type of method will work on every STL (Not only vectors, which is a bit better).
If you still want to use indexes, the way is:
for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
v[i].doSomething();
}
Using the auto operator really makes it easy to use as one does not have to worry about the data type and the size of the vector or any other data structure
Iterating vector using auto and for loop
vector<int> vec = {1,2,3,4,5}
for(auto itr : vec)
cout << itr << " ";
Output:
1 2 3 4 5
You can also use this method to iterate sets and list. Using auto automatically detects the data type used in the template and lets you use it.
So, even if we had a vector of string or char the same syntax will work just fine
A correct way of iterating over the vector and printing its values is as follows:
#include<vector>
// declare the vector of type int
vector<int> v;
// insert elements in the vector
for (unsigned int i = 0; i < 5; ++i){
v.push_back(i);
}
// print those elements
for (auto it = v.begin(); it != v.end(); ++it){
std::cout << *it << std::endl;
}
But at least in the present case it is nicer to use a range-based for loop:
for (auto x: v) std::cout << x << "\n";
(You may also add & after auto to make x a reference to the elements rather than a copy of them. It is then very similar to the above iterator-based approach, but easier to read and write.)
There's a couple of strong reasons to use iterators, some of which are mentioned here:
Switching containers later doesn't invalidate your code.
i.e., if you go from a std::vector to a std::list, or std::set, you can't use numerical indices to get at your contained value. Using an iterator is still valid.
Runtime catching of invalid iteration
If you modify your container in the middle of your loop, the next time you use your iterator it will throw an invalid iterator exception.
Here is a simpler way to iterate and print values in vector.
for(int x: A) // for integer x in vector A
cout<< x <<" ";
With STL, programmers use iterators for traversing through containers, since iterator is an abstract concept, implemented in all standard containers. For example, std::list has no operator [] at all.
I was surprised nobody mentioned that iterating through an array with an integer index makes it easy for you to write faulty code by subscripting an array with the wrong index. For example, if you have nested loops using i and j as indices, you might incorrectly subscript an array with j rather than i and thus introduce a fault into the program.
In contrast, the other forms listed here, namely the range based for loop, and iterators, are a lot less error prone. The language's semantics and the compiler's type checking mechanism will prevent you from accidentally accessing an array using the wrong index.
don't forget examples with const correctness - can the loop modify the elements. Many examples here do not, and should use cont iterators. Here we assume
class T {
public:
T (double d) : _d { d } {}
void doSomething () const { cout << _d << endl; return; }
void changeSomething () { ++_d; return; }
private:
double _d;
};
vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
iter->doSomething();
}
Note also, that with the C++11 notation, the default is to copy the element. Use a reference to avoid this, and/or to allow for original elements to be modified:
vector<T> v;
// ...
for (auto t : v) {
t.changeSomething(); // changes local t, but not element of v
t.doSomething();
}
for (auto& t : v) { // reference avoids copying element
t.changeSomething(); // changes element of v
t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
t.doSomething(); // element can not be changed
}
//different declaration type
vector<int>v;
vector<int>v2(5,30); //size is 5 and fill up with 30
vector<int>v3={10,20,30};
//From C++11 and onwards
for(auto itr:v2)
cout<<"\n"<<itr;
//(pre c++11)
for(auto itr=v3.begin(); itr !=v3.end(); itr++)
cout<<"\n"<<*itr;
int main()
{
int n;
int input;
vector<int> p1;
vector<int> ::iterator it;
cout << "Enter the number of elements you want to insert" << endl;
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> input;
p1.push_back(input);
}
for(it=p1.begin();it!=p1.end();it++)
{
cout << *it << endl;
}
//Iterating in vector through iterator it
return 0;
}
conventional form of iterator
If you use
std::vector<std::reference_wrapper<std::string>> names{ };
Do not forget, when you use auto in the for loop, to use also get, like this:
for (auto element in : names)
{
element.get()//do something
}
I'm very use to working with arrays and vectors, but now I'm playing with some STD::lists, as well as a custom list class I made.
Let's say I have a simple class, Stock.
//stock.h
class Stock{
public:
Stock(); //default constructor
Stock(string, double); //overloaded constructor
void setSymbol(string); //sets stock symbol
void setPrice(double);
string getSymbol();
double getPrice();
private:
string symbol;
double price;
};
Now in a separate file I have my int main to test.
#include "stock.h"
#include <list>
int main(){
list<Stock> portfolio;
Stock Google("GOOG", 500);
Stock Apple("APPL", 300);
Stock Chipotle("CMG", 200);
portfolio.push_back(Google);
portfolio.push_back(Apple);
portfolio.push_back(Chipotle);
}
Now if this was a vector or array, I would have no problem, I'm just completely loss on the linked-list equivalent of the following:
for(int i=0; i <portfolio.size(); i++){
portfolio[i].getSymbol();
portfolio[i].getPrice();
}
Or something along those lines...I have no lecture/training in Linked-Lists so I'm really trying to do my best in teaching myself--but I'm stuck on basic manipulation. I'm using STL::list right now, but really trying to make my own class as well.
for(int i= portfolio.begin(); i <portfolio.size(); i++)
If this worked for a std::vector, it was only by sheer accident. I have no idea how that might have worked for a vector.
std::any_stl_container::begin() returns an object called an "iterator". Specifically, an object of type std::any_stl_container::iterator. An iterator is kind of like a generalized pointer: it refers to an element in an STL container.
The iterator returned by begin is the iterator that references the first element in the list. You can move iterators around like pointers. For example:
std::list<Stock> portfolio;
...
std::list<Stock>::iterator currElem = portfolio.begin();
++currElem; //Now points to the second element in the list.
Stock &secondStock = *currElem;
In order to iterate over all of the elements in a list, you need two iterators: the first one, and the iterator for the element after the last element in the list. Fortunately, this is returned by the std::any_stl_container::end() function. So, your loop should look like:
typedef std::list<Stock>::iterator StockIt;
for(StockIt i = portfolio.begin(); i != portfolio.end(); ++i) /* Prefer pre-increment with iterators */
{
i->getSymbol();
i->getPrice();
}
This will work for any of the usual STL containers.
You have iterators as begin() and end() for std::list also:
for (list<stock>::iterator it = portfolio.begin() ; it != portfolio.end(); it++)
{
// use 'it' to access the current element (i.e. *it)
}
You have to use iterators. Every STL container has them, even vector. They behave similarly to pointers; they can be dereferenced with * or ->, they can be incremented, they can be compared.
for( list<Stock>::iterator it = portfolio.begin(); it != portfolio.end(); it++ ){
it->getSymbol();
it->getPrice();
}
An object of type std::list is very inefficient if you try to compute its length, because such an operation would have linear time.
Therefore with lists, you cannot compare iterators with the < and > operators. It is also ill-advised to try to get the nth element with the operator [].
Also, you should not mix begin() and size() which are respectively an iterator and an integer.
The proper way to iterate over an std::list is to use the pair of iterators begin() and end() and to increment your iterator until it reaches the end().
So, two ways:
for(std::list<stock>::const_iterator i = my_list.cbegin(); i != my_list.cend(); ++i)
{
// access a “const stock &” object via *i
}
or
for(std.:list<stock>::iterator i = my_list.begin(); i != my_list.end(); ++i)
{
// access a “stock &” object via *i
}