Why do variables get into for loops with zero length? - r

can somebody explain why for loops are executed even on variables with zero length? For example
listFunction<-function(listinput)
{
for (i in 1:length(listinput))
{listinput[i]<-listinput[i]+1
print("googats")
}
listinput
}
listB<-c()
listFunction(listB)
[1] "googats"
[1] "googats"
> listB
NULL
why does it iterate the loop twice rather than simply not go in at all?

Per official documentation, for loop
The syntax of the for loop is
for ( name in vector )
statement1
where vector can be either a
vector or a list. For each element in vector the variable name is set
to the value of that element and statement1 is evaluated. A side
effect is that the variable name still exists after the loop has
concluded and it has the value of the last element of vector that the
loop was evaluated for.
So, it will iterate through each element.
In your case,
for (i in 1:length(listinput))
{
listinput[i]<-listinput[i]+1
print("googats")
}
is like
for (i in 1:0)
{
listinput[i]<-listinput[i]+1
print("googats")
}
since there are 2 elements 1 and 0 in your vector, the loop body will be iterated twice.

Related

Modifying map while iterating over it in Go

Given the following code I would expected an infinite loop but the loop is being stopped at certain point.
m := make(map[int]string, 4)
m[0] = "Foo"
for k, v := range m {
m[k+1] = v
}
I cannot figure out what happen under the hood because different execution return different output. For example these are a few outputs from different executions:
map[0:Foo 1:Foo 2:Foo 3:Foo 4:Foo 5:Foo 6:Foo 7:Foo]
map[0:Foo 1:Foo]
map[0:Foo 1:Foo 2:Foo]
How range works in order to exit from loop at certain point and what is the exit condition?
Spec: For statements with range clause says the behavior is unpredictable:
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
Adding elements to the map you're ranging over, those entries may or may not be visited by the loop, you should not assume anything regarding to that.
Based on the language spec:
If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped.
So if the new elements are skipped, the for-loop eventually ends.
The other answers have already explained the behavior you observe with your snippet.
Because your title is rather generic but your snippet only covers the addition of map entries while iterating over the map, here is a complementary example that should convince you that "cross-removing" map entries while iterating over the map is a bad idea (Playground):
package main
import "fmt"
func main() {
m := map[string]int{"foo": 0, "bar": 1, "baz": 2}
for k := range m {
if k == "foo" {
delete(m, "bar")
}
if k == "bar" {
delete(m, "foo")
}
}
fmt.Println(m)
}
The spec says:
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced.
As a result, the program outputs either map[bar:1 baz:2] or map[baz:2 foo:0], but there is no way to tell which.

Why does my condition only eliminate the first key/value pair in my dictionary?

I'm currently working on a problem relating to dictionaries where you write a function that deletes all key/value pairs in which a value is larger than a given number. Here is the code:
def remove_numbers_larger_than(number, dict1):
for i, value in dict1.items():
if value > number :
del dict1[i]
return dict1
else:
return dict1
dict1 = {'animals': 6 , 'truck': 3, 'country': 2}
number = 2
print(remove_numbers_larger_than(number, dict1))
Normally I would expect to see output: {'country': 2} given that it is the only value smaller than the given number but instead I get output: {'truck': 3, 'country': 2}. It seems to be taking the initial condition and removing the first value but then the loop stops.
Only the first item is getting deleted because you immediately return from the function in the first iteration of the for loop. To loop through every value, you shouldn't return until after the for loop is over.
However, there's also another issue with the code. You are iterating through a list (dict1.items()) which will change when you remove items from the dictionary. An easy fix is to make a copy of the items list that you iterate over, allowing the original list to change without problems:
for i, value in list(dict1.items()):

is there an exception handling available for element() function when index>list of values?

data"aws_network_interface""node1"{
id="eni-0dfe5asdf7ajk5"
}
the output of above data source is a list of Private_ips with the length of 4
as
[10.198.10.1,10.198.10.2,10.198.10.3,10.198.10.4]
Here I am trying to create NLB with the target by IP.
I am also confused on how the index works in element() function -my requirement is to pick the 3rd element as [10.198.0.3] from the above list if my var.lbcount=1 and when my var.lbcount=2 I need to pick the 4th element from the above list as 10.198.10.4.
resource"aws_lb_target_group_attachment""tga"
{
target_group_arn="${aws_lb_target_group.tg.arn}"
target_id="${element(data.aws_network_interface.node1.private_ips,4}"
}
As I stated
index=4
I am getting target_id as a 1st element in the list as [10.198.10.1] which is wrong, how to throw an error or exception if the index is out of range of length of the list.
How can I make sure we should only allow 1,2,3 as the index in element() function and if we pass 4, which is more than the list of values the terraform to throw an error?
In general, Terraform would use list[0] again if length(LIST) = 3 and the current count.index = 4.
You can, however, use a simple conditional for your use-case (pseudocode):
count = "${var.MAX_INDEX > length(LIST) ? length(LIST) : var.MAX_INDEX"
This would set count to the length of the list if your MAX_INDEX is larger than the length of your list. Otherwise it would set count to your MAX_INDEX.

R - Writing a function to return binary output using if statement

Good day,
I am a beginner and trying to understand why I am getting the error below.
I am trying to create a function that would return 0 or 1 based on column values in data set.
LT = function(Lost.time) {
For (i in 1:dim(df)) {
if (df$Lost.time > 0) {
x = 1
}
else {
x = 0
}
return(x)
}
}
Error: no function to return from, jumping to top level In addition: Warning
message: In if (df$Lost.time > 0) { : the condition has length > 1 and only
the first element will be used> } Error: unexpected '}' in "}"
There are a couple of mistakes in the code:
R is case sensitive. Use for instead of For.
If you are looping over the entries in df$Lost.time, the individual elements should be addressed within the loop using df$Lost.time[i]. However, a loop is not necessary for this task.
An else statement should not begin on a new line of the code. The parser cannot know that the if statement is not finished after the first block. If the else statement is enclosed in curly braces like in } else { there will be no problem in this sense.
The parameter passed to the function is not suitable. Maybe you could pass df, instead of Lost.time, but it may be necessary to rewrite parts of the function.
The use of 1:dim(df) in the for loop should work, but it will trigger a warning message. It is better to use 1:nrow(df).
Those are syntax problems. However, the main issue is probably what has been addressed in the answer by #TimBiegeleisen: In the loop you are checking for each of the ̀nrow(df) elements of df$Lost.time whether a specific condition is fulfilled. It therefore does not seem to make sense to have a single binary result as return value. The purpose of the function should be clarified before it is implemented.
An alternative to this function could be constructed in a one-liner with ifelse.
It is not clear what you actually want to return in your function. return can only be called once, after which it will return a single value and the function will terminate.
If you want to get a vector which will contain 1 or 0 depending on whether a given row in your data frame has Lost.time > 0, then the following one liner should do the trick:
x <- as.numeric(df$Lost.time > 0)
If loops are used for writing a function indices should be used for each element.
Create a variable(x) in your dataframe, if the statements goes true it prints 1 else 0
LT = function(Lost.time) {
for (i in 1:dim(df)) {
if (as.numeric(df$Lost.time[i]) > 0) {
df$x[i] <- 1
}else{
df$x[i] <- 0
}
}
}

Method vector::clear doesn't clear a two dimensional vector

Thank you very much for the answer.
The reason that makes me think about checking the content of the vector is that even after I overwrite it, the same (strange) values remain. My purpose is to generate iteratively some random variables and put them in the two dimensional vector. I give you my code, maybe I am doing something wrong:
while (nbre_TTI_tempo != 0 )
{
srand(time(NULL)) ;
while (nbre_UE_tempo != 0 )
{
vect.clear() ;
nbre_PRB_tempo = nbre_PRB ;
while (nbre_PRB_tempo != 0)
{
value = rand() % 15 + 1 ; // generating random variables between 1 and 15
vect.push_back(value) ;
nbre_PRB_tempo -- ;
}
All_CQI.push_back(vect) ;
nbre_UE_tempo -- ;
}
// Do business
All_CQI.clear();
} .// end while
At the first round, everything goes well, but at the second one, this is what I find in the vector after the use of the method "clear":
158429184
14
15
158429264
10
9
158429440
5
1
And when I try to overwrite it, I find:
158429184
14
15
158429264
10
9
158429440
5
1
Which are the same values as before using the method "push_back".
Do you think I'm doing something wrong in my code?
Thank you very much in advance for your help.
For your purpose, if empty() returns true, you should trust that it is empty and SHOULD NOT check for individual elements. It is illegal to access the contents of an empty vector thus and can cause memory access errors.
The reason you find values is because the actual memory locations are not overwritten immediately- they are only marked as invalid. Until some other object is allocated the same memory, the data may remain as it is - but there is no way to be sure - the implementation is left to the compiler.
Looks like you are using the array operator[] to access the elements. To be safer, use the iterator or the .at() method to access the elements. Both these methods perform bounds checking and will not let you go beyond the last valid element

Resources