how to loop only half of the elements in C++ vector data structure using auto keyword
vector<string> InputFIle;
void iterateHalf(){
/* iterate only from begin to half of the size */
for (auto w = InputFIle.begin(); w != InputFIle.end(); w++) {
cout << *w << " : found " << endl;
}
}
You need to compute begin and end of your loop, i.e. first and last_exclusive.
#include <vector>
#include <numeric>
#include <iostream>
int main(){
std::vector<int> vec(16);
std::iota(vec.begin(), vec.end(), 0);
size_t first = 3;
size_t last_exclusive = 7;
//loop using indices
for(size_t i = first; i < last_exclusive; i++){
const auto& w = vec[i];
std::cout << w << " ";
}
std::cout << "\n";
//loop using iterators
for(auto iterator = vec.begin() + first; iterator != vec.begin() + last_exclusive; ++iterator){
const auto& w = *iterator;
std::cout << w << " ";
}
std::cout << "\n";
}
Related
Why doesn't the range-based loop with auto display addresses?
The for loop:
for (int i = 0; i < s; i++) cout << &ar[i] << endl;
works normally, but range-based loop with auto doesn't:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int ar[] = { 12,-23,0,1,2 };
int s = sizeof(ar) / sizeof(int);
int * m = &ar[0];
sort(&ar[0], m+ s);
for (auto m : ar)
cout << m << endl;
cout << endl;
for (auto m : ar)
cout << &m << endl;
cout << endl;
for (int i = 0; i < s; i++)
cout << &ar[i] << endl;
system("pause");
}
With the auto m you are passing (array) elements by value / copy in your range based loop:
for (auto m : ar) { // pass by value
std::cout << &m << ' '; // prints addresses of copies, not the actual array elements
}
This means m becomes a copy of an array element in each iteration and has its own address in the memory.
If you passed by reference (auto& m) or a reference to const (const auto& m), you would observe the expected results:
for (auto& m : ar) { // pass by reference
std::cout << &m << ' '; // prints addresses of the actual array elements
}
Now m is an actual array element and &m represents the array element address as expected.
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
I wanted to use std::count() but I am not able to do it right. I tried to do the following:
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
while (it != numbers.begin() && it != numbers.end())
{
++it;
*it = count(it, numbers.begin(), numbers.end());
cout << " " << *it;
}
cout << endl;
}
return 0;
}
But it gives me an error:
binary == no operator found which takes a left hand operator type 'int' (or there is not acceptable conversion).
I know I am doing something wrong.
I also tried a few more things, like int numb = std::count(numbers.begin()), numbers.end(), *it), but it didn't work either. So, I want to know if there is a special operator to count values in a list.
You need to look at the signature for std::count again. It takes three parameters std::count(InputIterator first, InputIterator last, const T& val); and it returns the number of occurrences of val in your data set. So something like this should work for you where theNumber is the number you're counting.
#include <algorithm>
int occurrences = std::count(numbers.begin(), numbers.end(), theNumber);
You are not using iterators correctly (you are modifying it while you are still using it to iterate the list), and you are not calling std::count() correctly.
The code should look more like this instead:
#include <iostream>
#include <list>
#include <algorithm>
#include <cstdlib>
int main()
{
std::list<int> numbers;
int numb;
for (int i = 0; i < 10; i++)
numbers.push_back(std::rand() % 20);
std::list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
numb = std::count(numbers.begin(), numbers.end(), *it);
std::cout << *it << " " << numb << std::endl;
}
/* or:
for (int value : numbers)
{
numb = std::count(numbers.begin(), numbers.end(), value);
std::cout << value << " " << numb << std::endl;
}
*/
return 0;
}
But, like others said, you should use a std::map to track the counts, so you can account for duplicates, eg:
#include <iostream>
#include <list>
#include <map>
#include <cstdlib>
int main()
{
std::list<int> numbers;
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numbers.push_back(rand() % 20);
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
numb[*it]++;
/* or:
for (int value : numbers)
numb[value]++;
*/
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
Which can be reduced to this:
#include <iostream>
#include <map>
#include <cstdlib>
int main()
{
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numb[rand() % 20]++;
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
In general, using a map is a better approach to your problem, but if you have to solve it using lists here is one possible solution:
#include <iostream>
#include <algorithm>
#include <list>
int main()
{
std::list<int> numbers, unique_num, numb;
int num;
// Create both the original list and a list that
// will be left with only unique numbers
for (int i = 0; i<10; i++){
num = rand() % 20;
numbers.push_back(num);
unique_num.push_back(num);
}
// Sort and select the unique numbers
unique_num.sort();
unique_num.unique();
// Count unique numbers and store the count in numb
std::list<int>::iterator iter = unique_num.begin();
while (iter != unique_num.end())
numb.push_back(count(numbers.begin(), numbers.end(), *iter++));
// Print the results
for(std::list<int>::iterator iter1 = unique_num.begin(), iter2 = numb.begin();
iter2 != numb.end(); iter1++, iter2++)
std::cout<< "Number " << *iter1 << " appears " <<
*iter2 << ( *iter2 > 1 ? " times " : " time" ) << std::endl;
return 0;
}
The program uses another list, unique_num, to hold unique numbers occurring in numbers. That list is initially created identical to numbers and is then sorted and the duplicates are removed.
The program then iterates through numbers in that unique list and uses count to get the number of occurrences of each of them in the original numbers list. The number of occurrences is then stored in a new list, numb.
When printing, the program uses a ternary operator to check whether it should print "time" or "times" depending whether the result implies one or more than one occurrence.
Note - if you want different list values each time you run your program you need to change the random seed using srand. Include the header #include <time.h> in your program and the line srand(time(NULL)); at the beginning of your main.
I suggest you use a map:
map<int, int> counts;
for(int val : Numbers)
++counts[val];
WITH ADDITIONAL MEMORY:
You can use buckets, to get complexity O(N + MAX_NUM). So when MAX_NUM <= N we have O(N):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
const int MAX_NUM = 20;
const int N = 10;
int main() {
std::list<int> numbers;
int buckets[MAX_NUM];
std::fill(buckets, buckets + MAX_NUM, 0);
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (int i = 0; i < MAX_NUM; i++) {
if (buckets[i]) std::cout << "value " << i << " appears in the list " << buckets[i] << " times." <<std::endl;
}
return 0;
}
For big data i would recommend using std::unordered_map for buckets and then geting complexity O(N) (thanks to hashing):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
#include <unordered_map>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
std::unordered_map<int, int> buckets;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (auto & k_v : buckets) {
std::cout << "value " << k_v.first << " appears in the list " << k_v.second << " times." <<std::endl;
}
return 0;
}
WITHOUT ADDITIONAL MEMORY:
In more universal way, you can use std::vector instead of std::list and std::sort on it, and then count value changes in a simple for. Complexity is O(N log N):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::vector<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
std::sort(numbers.begin(), numbers.end());
//printing answers for sorted vector
if (numbers.size() > 0) {
int act_count = 1;
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] != numbers[i -1]) {
std::cout << "value " << numbers[i-1] << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
}
std::cout << "value " << numbers[numbers.size() - 1] << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
You can also do the above on std::list, getting also O(nlogn), but can't use std::sort:
#include <iostream>
#include <list>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
numbers.sort();
//printing answers for sorted list
if (!numbers.empty()) {
int act_count = 0;
auto prev = numbers.begin();
for (auto it = numbers.begin(); it != numbers.end(); it++) {
if (*it != *prev) {
std::cout << "value " << *it << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
prev = it;
}
std::cout << "value " << *prev << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
I am trying to store boost integers cpp_int in an ordered set and check for next and prev elements using below code:
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/unordered_set.hpp>
#include <iostream>
namespace mp = boost::multiprecision;
using boost::unordered_set;
using namespace std;
int main() {
set<mp::cpp_int> st;
set<mp::cpp_int>::iterator it, it1, it2;
//pair<set<mp::cpp_int>::iterator,bool> res;
boost::tuples::tuple<set<mp::cpp_int>::iterator, bool> tp;
int i = 0, temp;
while(i<10){
cin>>temp;
tp = st.insert(temp);
it = get<0>(tp);
it1 = prev(it);
it2 = next(it);
cout<<*it1<<endl;
//cout<<*it2<<endl;
i++;
}
return 0;
}
However, the above code does not work as expected and crashes after couple of inputs. One such crashing sequence of inputs is:
0
1
2
3
4
0
What is the proper way of using set and iterators when using boost?
You need to check that there is a previous / next element before dereferencing the it1 and it2, e.g.:
std::set<mp::cpp_int> s;
for (size_t i = 0; i < 10; ++i){
std::cin >> temp;
auto p = s.insert(temp);
if (p.second) { // insertion succeed
auto it = p.first;
std::cout << "Inserted: " << *it << '\n';
if (it != s.begin()) { // not the first, there is a previous element
auto it1 = std::prev(it);
std::cout << "Previous: " << *it1 << '\n';
}
else {
std::cout << "Previous: None\n";
}
auto it2 = std::next(it);
if (it2 != s.end()) { // there is a next element
std::cout << "Next: " << *it2 << '\n';
}
else {
std::cout << "Next: None\n";
}
}
}
Also, if you want to find the previous and next elements of an existing element, you should use std::set::find, not std::set::insert:
auto it = s.find(temp);
if (it != s.end()) {
// Same code as above.
}
In my C++ script, I want to insert some elements of a list into a vector (from the beginning of list to a specific position "it"), and then try to add the vector at the top of the list and keeping the same order of the vector but I get unwanted additional elements in the vector.
Here is my code:
#include <iostream>
#include <iterator>
#include <vector>
#include <list>
int main() {
std::list<int> mylist;
for (int i = 0; i < 10; i++)
mylist.push_back(i * 10);
for (std::list<int>::iterator i = mylist.begin(); i <= mylist.end(); ++i) {
std::cout << *i << ", ";
}
std::cout << std::endl;
std::advance(it, 6);
std::cout << "The 6th element in mylist is: " << *it << std::endl;
// The vector that will contain mylist elements
std::vector<int> intAdeplacer;
intAdeplacer.insert(intAdeplacer.end(), mylist.begin(), it);
std::cout << std::endl;
std::cout << "Nombre d'éléments dans le vecteur : " << intAdeplacer.size() << std::endl;
std::cout << std::endl;
// see the content of the vector
std::cout << "Le vecteur de deplacement contient : " << std::endl;
for (std::vector<int>::const_iterator i = intAdeplacer.begin();
i <= intAdeplacer.end(); ++i) {
std::cout << *i << ", ";
}
I get this output:
Le vecteur de deplacement contient :
0, 10, 20, 30, 40, 134985,
134985 is not wanted..
// Insert in front of the list the values of the vector and keeping the same order of elements in the vector
for (std::vector<int>::const_iterator i = intAdeplacer.end();
i >= intAdeplacer.begin(); --i) {
mylist.push_front(*i);
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << "nouvelle composition de mylist : " << std::endl;
for (std::list<int>::const_iterator j = mylist.begin(); j != mylist.end();
++j) {
std::cout << *j << ", ";
}
std::cout << std::endl;
std::cout << std::endl;
// erasing the added elements from mylist
std::list<int>::iterator debut = mylist.begin();
std::list<int>::iterator fin = mylist.end();
std::advance(fin, 6);
mylist.erase(debut, fin);
for (std::list<int>::iterator j = mylist.begin(); j <= mylist.end(); ++j) {
std::cout << *j << ", ";
}
return 0;
}
If it is an iterator pointing at the 6th element of your list, the following insert() will insert from begin() (included) to it (excluded) into the vector:
intAdeplacer.insert(intAdeplacer.end(), mylist.begin(), it);
So you'll have only 5 elements, from 0 to 40. Unfortunately your printing loop does include the end() of the vector, which is out of range. This is why you get this strange trailing number.
Just correct your loop into:
for (auto i = intAdeplacer.begin(); i != intAdeplacer.end(); ++i) {
std::cout << *i << ", ";
}
Or consider this alternate range-for syntax:
for (auto &element: intAdeplacer) {
std::cout << element << ", ";
}
I need help increasing the values of elements in mylist and assigning that new list to mylist3. I tried doing it as you would an array or vector but it did not work. Any help appreciated. Thanks in advance.
std::list<int> mylist(myarray, myarray + sizeof(myarray) / sizeof(int));
cout << "mylist contains: ";
for (std::list<int>::iterator b = mylist.begin(); b != mylist.end(); ++b)
cout << ' ' << *b;
cout << "\n" << endl;
std::list<int> mylist3(10);
for (int z = 0; z < 10; z++) {
mylist3[z] = mylist[z] + 5;
}
cout << "mylist3 contains: ";
for (std::list<int>::iterator f = mylist3.begin(); f != mylist3.end(); ++f)
cout << ' ' << *f;
Easily done with the standard library:
std::transform(mylist.begin(),mylist.end(),std::back_inserter(mylist3),
[](int i){return i+5;});
Here's one way of doing this fairly readably:
#include <iostream>
#include <iterator>
#include <list>
std::list<int> mylist(std::begin(myarray), std::end(myarray)), mylist3 = mylist;
for (int & n : mylist3)
n += 5;
std::cout << "mylist3 contains:";
for (int n : mylist3)
std::cout << ' ' << n;
std::cout << '\n';