Logic error with my range-for loop - c++

I'm studying C++ as a beginner (I started 2 months ago) and I have a problem with my simple code. I tried to set the value of each element in this vector to 0 but I can't understand why it doesn't work :
vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int x : numbers) x = 0;
I know that I may sound stupid but I am a beginner. If I try to do the same thing with a traditionally for loop it works, why ?

It does not change the values in the array, because in each iteration the value in the array is assigned to to x and you are changing x and not the value in the array.
Basically the range based loop is similar to the following ordinary for loop:
for(int i = 0; i < numbers.length(); i++)
{
int x = numbers[i];
//your code
}
.
For more information check out the c++ documentation:
http://en.cppreference.com/w/cpp/language/range-for .
It states:
range_expression is evaluated to determine the sequence or range to
iterate. Each element of the sequence, in turn, is dereferenced and
assigned to the variable with the type and name given in
range_declaration.
Also you will find there the example "Shmil The Cat" has posted and more examples which will help you understand how the range loop works.

for (int& x : numbers) x = 0;
In order to mutate the container elements one shall use reference for the range-loop iterating variable (by default, the iterating variable is a copy of the current iterated element)

It does not work, you don't have any reference to the elements in the array via your foreach. Think about this, you are retrieving elements in array numbers and making a copy of copy in x which does not have reference. so any changes that x undergoes does not reflect in numbers arrays.
so work how #Shmil The Cat suggested. or traditional way will also do the job like you said.

The items of vector are not assigned the value (zero in this case)because ranged based loops consider container as copy of original until explicitly passed the reference of original container.
Do use
for (int& x : numbers) x = 0;
as suggested by #Shmil The Cat

To help you understand, here is how you can read the below:
For every element in numbers, copy data into x and set x to 0. // Now this doesn't touch the value in the vector.
for (int x : numbers)
x = 0;
Reading the below loop:
For every element in numbers, make a reference to it, and change the value through the reference to 0. This on the other hand, changes the values in the vector.
for (int &x : numbers)
x = 0;

If all you want is to set a particular value to all elements it would be better to use std::fill
std::fill(numbers.begin(), numbers.end(), 0);

Related

Using nested [ ] operations for std::vector

I am quite new to C++, and i have tried searching for an answer to this and running tests, but many times I'm having trouble figuring out what causes specific behaviors.
My question relates to using nested [ ] operators to access or modify elements in a loop - example:
//Declare
std::vector<int> a1 {10,20,30,40} ;
std::vector<int> a2 {2,3} ;
int S2 = a2.size() ;
//Loop
for(int i = 0 ; i < S2 ; i++){
a1[a2[i]] = a1[a2[i]] + 5000 ;
}
Is this considered ok? I'm asking not only in terms of common practice, but also in terms of efficiency and any other potential factor I need to consider.
Am I supposed to first store a[i] inside a temporary variable inside the loop and then use it to modify my element in vector a2?
I do know that its probably not the best structure and I should be using some other data structure to do this kind of thing, but I just want to understand if this is ok or if it might cause some undefined behavior.
I am developer for a finite element calculation software.
We use this technique in order to access the values inside an element. It helps us to save a lot of memory
BUT: Be aware that it spoils your cache locality. Don't use it in heavy loops, if you can avoid it.
If you need a range checks and performance is not important, you can consider using the at operator of the std::vector
for(const auto & index :a2) {
a1.at(index) += 5000;
}
The at function automatically checks whether n is within the bounds of valid elements in the vector, throwing an out_of_range exception if it is not (i.e., if n is greater than, or equal to, its size). This is in contrast with member operator[], that does not check against bounds.
Moreover, consider using a range based loop
//Loop
for(const auto & index :a2) {
a1[index] += 5000;
}
This is perfectly correct.
But in fact, you just want to iterate the elements of a standard container. C++ allows the range based for statement for that use case:
for (index: a2) {
a1[index] += 5000;
}
I find it more readable even if it is mainly a matter of taste...
Disclaimer: this code makes no control of the validity of the elements of a2 as index of a1.
Looks okay to me. There is no need to create an explicit copy of a2[i].
The only issue I see with something like this is that the argument inside [] should be of type std::size_t instead of int. These integer types encompass different ranges of values, and while std::size_t is an unsigned integer type, int is a signed integer. Beware of using negative indexes or indexes past the last element will likely result in undefined behavior due to out-of-bounds access. But if you can guarantee that the values in a2 are always valid indexes for a1, then these int values will implicitly be converted to std::size_t and things works properly (which seems to be the case in the code example in your question).
I also suggest to convert the loop variable i to std::size_t (and use ++i instead of i++ if you want to be perfect:).
In modern C++, you can also use a range-based for so you don't have use an explicit index variable for accessing a2 values at all:
for (auto indexFromA2 : a2)
a1[indexFromA2] += 5000;
This is less error-prone, because you have to write less logic for managing the element access (and don't have to spell out the types).
I would somehow ensure that the elements in a1 defined in a2 do really exist before trying to access them, otherwise you run out of bounds.
But in regards of nested [] this is fine and there's no need to create another copy of a2 to access a1. The compiler is just unwrapping your expression from inside out.
You can still simplify your code a bit
//Declare
std::vector<int> a1 {10,20,30,40} ;
std::vector<int> a2 {2,3} ;
//Loop
for(int i = 0 ; i < a2.size() ; i++){
if(a1.size()-1 < a2[i]){break;}
a1[a2[i]] += 5000 ;
}

Using "find" to access a value in vector

So I have been brushing up a bit on c++ and found out I am very rusty in comparison to my other languages. I have been working on this problem from codewars.com
Given a list lst and a number N, create a new list that contains each number of lst at most N times without reordering. For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2], drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3, which leads to [1,2,3,1,2,3].
To accomplish this task I wanted to create a multidimentional vector to hold unique values of the provided list in the first dimension and corresponding number of occurences in the second dimension. However, I was unfamiliar with c++'s syntax to accomplish this, so I just made 2 separate vectors.(instances, countOfInstance)
Essentially what my algorithm will do is:
loop through the provided array(arr)
check to see if the value in "arr" does not exists in "instances"
If not found then push the value in "arr" to "instances",
add a counting value of 1 that corresponds to this index in "countOfInstance"
and then add the value in "arr" to the nFilteredVector.
If the value in "arr" is found in "instances" then:
Find the index value of "arr" in "instances"
Use this index to find its corresponding count value in "countOfInstances"
Determine if the count is less than the provided "N"
if less than "N" add to "nFilteredVector"
Then increment the value in "countOfInstances"
However, when I try to access the index of "CountOfInstances" with index of "instances" i get an odd error
no viable overloaded operator[] for type 'std::vector'
if (countOfInstances[std::find(instances.begin(), instances.end(),arr[i])] <=2){
Correct me if I am wrong, but it is my understanding that the find function returns the index value of the found element. I was wanting to use that index value to access "countOfInstances" vector.
Can someone please help me figure out the correct syntax of what I am looking for. Bonus points for integrating "instances" and "countOfInstance" as a multidimentional vector!!
#include <algorithm>
std::vector<int> deleteNth(std::vector<int> arr, int n)
{
std::vector<int> nFilteredVector;
std::vector<int> instances;
std::vector<int> countOfInstances;
for (int i =0; i < arr.size();i++){
if(std::find(instances.begin(), instances.end(),arr[i])==instances.end()){//value not found need to add corresponding value to instances vector then add an element of 1 to the correpeonding index of the countOfInstance vector.
instances.push_back(arr[i]);
countOfInstances.push_back(1);
nFilteredVector.push_back(arr[i]);
}else{ // value is found just need to increment the value in countOfInstances
//find the instance of the value in arr in the instance vector, use that value to find the corresponding value in countOfInstance
if (countOfInstances[std::find(instances.begin(), instances.end(),arr[i])] <=n){
nFilteredVector.push_back(arr[i]);
}
countOfInstances[std::find(instances.begin(), instances.end(),arr[i])]++;
}
return nFilteredVector;
}
Here are some examples of what codewars will be testing for
{
Assert::That(deleteNth({20,37,20,21}, 1), Equals(std::vector<int>({20, 37, 21})));
Assert::That(deleteNth({1,1,3,3,7,2,2,2,2}, 3), Equals(std::vector<int>({1, 1, 3, 3, 7, 2, 2, 2})));
}
If what you are trying to achieve is get the index of the found item in a std::vector, the following does this job using std::distance:
#include <algorithm>
#include <vector>
auto iter = std::find(instances.begin(), instances.end(),arr[i]);
if ( iter != instances.end())
{
// get the index of the found item
auto index = std::distance(instances.begin(), iter);
//...
}
I believe std::find return an iterator on instances. You cannot use an iterator from one list on another and you cannot use an iterator as an index.
What you could do is use
std::find(instances.begin(), instances.end(), arr[i]) - instances.begin()
as your index. This is a bit ugly, so you might also want to look a bit more at iterators and how to use them.

How to create a circular array?

I am trying to create a circular reference to array. For example,
float arr1[10] = {0,1,2,3,4,5,6,7,8,9};
Then I use a variable in loop to access elements of array.
for (int i=0;i<10;i++){
std::cout<<arr1[i]<<std::endl;
//other processing using arr1[i] indexing
}
Here, I can only use i<=10. If I want to make i<=16 and if i>10 then index should go to arr1[0] and proceed from there. What are preferable or recommended ways to do this?
You need to use the modulo operator %.
14 % 10 = 4 So just do this with the index you use to access it.
You should use like #Jdman1699 said the modulo operator. Here you find an example:
int position; //the position you want to get
float out = arr1[position%10];
For your specific program, I would simply suggest putting your base for loop inside of another for loop (as it seems that you want to print out all elements of the array many times over, considering your source code). This is because accessing element n is no different than accessing element n + 10. However, if you are planning to create some sort of function to access any element of the array, I would use the modulo operator-base 10. Maybe,
unsigned long int newidx = iptidx%10;
and then work with newidx.
May be u r looking for...
for (int i=0;i<10;i++){
std::cout<<arr1[i%10]<<std::endl;
//other processing using arr1[i] indexing
}

Translating the following C++ code into Nim

I'm trying to learn Nim by converting different pieces of code, and I've stumbled upon something which I've never seen before.
#include<bits/stdc++.h>
...
for(int t=q&1?u+x:u+x>>1;t>1;)t/=p[++cnt]=sieve[t];
...
sort(p+1,p+cnt+1);
I understand what the ternary operator is and how it works, what I don't quite get is what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers). How does using an increment as the index of "p" work?
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does (the fact that it's taking an integer added to an array obviously doesn't help).
Lets first start of by making the code a little more readable. A little bit of whitespace never hurt anybody.
for(int t = (q & 1? u + x: u + x >> 1); t > 1;)
{
t /= p[++cnt] = sieve[t];
}
what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers)
So t is being set to either u + x or u + x >> 1 depending on what q & 1 is. Then inside the loop we are dividing t by whatever the value of sieve at the index of t is. We are also assign that value to the p array at the position of ++cnt. ++cnt is using the pre increment operator to increase the value of cnt by 1 and then using that value for the index of p.
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does
For this I am assuming they are using the std::sort() function. When dealing with arrays the name of the array is treated as a pointer to the first element of the array. So when we see sort(p+1,p+cnt+1); you can translate it to sort(one from the begining of the array, cnt + 1 elements from the begining of the array);. So this is going to sort all of the elements in the array from one from the begining of the array to one less than cnt + 1 elements from the begining of the array.
Are you trying to learn Nim as you said, or trying to learn C? Both things you asked about are pretty basic c:
++cnt has the side effect (cnt=cnt+1) combined with the value that cnt ends up with. That value is used as the index. The side effect is a side effect.
p+1 and p+cnt are each pointers. The name of an array is treated as a constant pointer to the first element of that array in most uses within C. A pointer plus an integer is another pointer, pointing that number of elements past the original.

for_each and transform

for_each(ivec.begin(),ivec.end(),
[]( int& a)->void{ a = a < 0 ? -a : a;
});
transform(ivec.begin(),ivec.end(),ivec.begin(),
[](int a){return a < 0 ? -a : a;
});
I am currently learning lambdas and I am curious how the two implementations, that I have posted above, differ?
The two implementations you show do not differ logically (assuming you get the first version right by adding a return). The first one modifies elements in place while the last one overwrites its elements with new values.
The biggest difference I see, with transform you just can pass abs instead of a lambda that reimplements it.
transform is what would, in a functional language, be called map. That is, it applies a function to every element in the input range, and stores the output into an output range. (So it is generally intended to not modify the inputs, and instead store a range of outputs)
for_each simply discards the return value from the applied function (so it might modify the inputs).
That's the main difference. They are similar, but designed for different purposes.
This first version:
for_each(ivec.begin(),ivec.end(),
[]( int& a)->void{ a = a < 0 ? -a : a;
});
works by calling the lambda function
[]( int& a)->void{ a = a < 0 ? -a : a; }
once for every element in the range, passing in the elements in the range as arguments. Accordingly, it updates the elements in-place by directly changing their values.
This second version:
transform(ivec.begin(),ivec.end(),ivec.begin(),
[](int a){return a < 0 ? -a : a;
});
works by applying the lambda function
[](int a){return a < 0 ? -a : a;}
to each of the elements in the range ivec.begin() to ivec.end(), generating a series of values, and then writing those values back to the range starting at ivec.begin(). This means that it overwrites the original contents of the range with the range of values produced by applying the function to each array element, so the elements are overwritten rather than modified in-place. The net effect is the same as the original for_each, though.
Hope this helps!