Function to find a prime integer on R [duplicate] - r

This question already has answers here:
Prime number function in R
(11 answers)
Closed 2 years ago.
Why isn't my R code working (i.e. doesn't find prime numbers)?
x <- c(1:50)
prime <- function(x){if(x %% (2:(x-1)) == 0) {
print("p")
}
else {
print("np")
}}

There's a few issues here.
Per #r2evans comment, the if condition needs to take an input parameter of length 1. You can get around this using the all command.
Your if condition is logically wrong. If the mod operator is equal to 0 then it is NOT prime. If fact you want to do != 0.
2 is considered to be a prime number. Your logic won't work for 2 because 2%2 = 0. As such you need to handle that case differently. Or the function needs to start working at 3.
Here is a working version:
prime <- function(x){
if(x == 2){
print("p")
}
else if(all(x %% (2:(x-1)) != 0)) {
print("p")
} else {
print("np")
}
}
> prime(2)
[1] "p"
> prime(3)
[1] "p"
> prime(4)
[1] "np"
> prime(5)
[1] "p"
> prime(6)
[1] "np"
> prime(7)
[1] "p"

Related

strsplit(rquote, split = "")[[1]] in R

rquote <- "r's internals are irrefutably intriguing"
chars <- strsplit(rquote, split = "")[[1]]
This question has been asked before on this forum and has one answer on it but I couldn't understand anything from that answer, so here I am asking this question again.
In the above code what is the meaning of [[1]] ?
The program that I'm trying to run:
rquote <- "r's internals are irrefutably intriguing"
chars <- strsplit(rquote, split = "")[[1]]
rcount <- 0
for (char in chars) {
if (char == "r") {
rcount <- rcount + 1
}
if (char == "u") {
break
}
}
print(rcount)
When I don't use [[1]] I get the following warning message in for loop and I get a wrong output of 1 for rcount instead of 5:
Warning message: the condition has length > 1 and only the first element will be used
strsplit is vectorized. That means it splits each element of a vector into a vectors. To handle this vector of vectors it returns a list in which a slot (indexed by [[) corresponds to a element of the input vector.
If you use the function on a one element vector (single string as you do), you get a one-slot list. Using [[1]] right after strsplit() selects the first slot of the list - the anticipated vector.
Unfortunately, your list chars works in a for loop - you have one iteration with the one slot. In if you compare the vector of letters against "r" which throws the warning. Since the first element of the comparison is TRUE, the condition holds and rcount is rised by 1 = your result. Since you are not indexing the letters but the one phrase, the cycle stops there.
Maybe if you run something like strsplit(c("one", "two"), split="") , the outcome will be more straightforward.
> strsplit(c("one", "two"), split="")
[[1]]
[1] "o" "n" "e"
[[2]]
[1] "t" "w" "o"
> strsplit(c("one", "two"), split="")[[1]]
[1] "o" "n" "e"
> strsplit(c("one"), split="")[[1]][2]
[1] "n"
We'll start with the below as data, without [[1]]:
rquote <- "r's internals are irrefutably intriguing"
chars2 <- strsplit(rquote, split = "")
class(chars2)
[1] "list"
It is always good to have an estimate of your return value, your above '5'. We have both length and lengths.
length(chars2)
[1] 1 # our list
lengths(chars2)
[1] 40 # elements within our list
We'll use lengths in our for loop for counter, and, as you did, establish a receiver vector outside the loop,
rcount2 <- 0
for (i in 1:lengths(chars2)) {
if (chars2[[1]][i] == 'r') {
rcount2 <- rcount2 +1
}
if (chars2[[1]][i] == 'u') {
break
}
}
print(rcount2)
[1] 6
length(which(chars2[[1]] == 'r')) # as a check, and another way to estimate
[1] 6
Now supposing, rather than list, we have a character vector:
chars1 <- strsplit(rquote, split = '')[[1]]
length(chars1)
[1] 40
rcount1 <- 0
for(i in 1:length(chars1)) {
if(chars1[i] == 'r') {
rcount1 <- rcount1 +1
}
if (chars1[i] == 'u') {
break
}
}
print(rcount1)
[1] 5
length(which(chars1 == 'r'))
[1] 6
Hey, there's your '5'. What's going on here? Head scratch...
all.equal(chars1, unlist(chars2))
[1] TRUE
That break should just give us 5 'r' before a 'u' is encountered. What's happening when it's a list (or does that matter...?), how does the final r make it into rcount2?
And this is where the fun begins. Jeez. break for coffee and thinking. Runs okay. Usual morning hallucination. They come and go. But, as a final note, when you really want to torture yourself, put browser() inside your for loop and step thru.
Browse[1]> i
[1] 24
Browse[1]> n
debug at #7: break
Browse[1]> chars2[[1]][i] == 'u'
[1] TRUE
Browse[1]> n
> rcount2
[1] 5

How do I compare 2 strings that are not exactly the same in R? [duplicate]

This question already has an answer here:
How to match a string with a tolerance of one character?
(1 answer)
Closed 2 years ago.
So I would like my code below to return TRUE, even as the front 2 letters are different.
Is there a way to accomplish this? I know == does not work as it compares both exactly.
if("UKVICTORIA" == "USVICTORIA") {
print("TRUE")} else {
print("FALSE")
}
}
Use agrepl
> agrepl("UKVICTORIA", "USVICTORIA", max.distance = 1)
[1] TRUE
Note, if there is an extra character (Z), it returns FALSE
> agrepl("UZKVICTORIA", "USVICTORIA", max.distance = 1)
[1] FALSE
Remove first two characters and check the number of unique values.
length(unique(sub(".{2}", "", c("UKVICTORIA", "USVICTORIA")))) == 1
#[1] TRUE

Why the sad text is positive? [duplicate]

This question already has answers here:
Why does "one" < 2 equal FALSE in R?
(2 answers)
Closed 3 years ago.
I have a string and while comparing with number it does not break and say that this is positive, any hints why this happens?
x <- "The day is bad, I don't like anything! I feel bad and sad really sad"
if (x == 0) {
print("x is equal to 0")
}else if (x > 0) {
print("x is positive")
}else if (x < 0 ){
print("x is negative")
}
The result is:
"x is positive"
?'>'
...If the two arguments are atomic vectors of different types, one is
coerced to the type of the other, the (decreasing) order of precedence
being character, complex, numeric, integer, logical and raw...
So while you compare x which is character vector, to 0, that is numeric type, former is converted to character '0':
x == 0 evaluates to FALSE because "The day is bad..." != "0";
x < 0 evaluates to FALSE because while ordered, 0 is placed before "The day is bad..." :
...Comparison of strings in character vectors is lexicographic within
the strings using the collating sequence of the locale in use...
sort(c(x, 0))
#[1] "0"
#[2] "The day is bad, I don't like anything! I feel bad and sad really sad"
Meaning that x is thought as greater than '0' because of the lexicographic order.
Finally x > 0 evaluates to TRUE because '0' precedes 'The day is bad, I dont...' and your code returns [1] x is positive
And if, trying to prove our hypothesis, we ask ourselves, whether Chuck Norris is able to beat the Infinity, we find that it is not the case:
'Chuck Norris' > Inf
# [1] FALSE
In contrast, Keith Richards, as anybody would expect, have no problem with that:
'Keith Richards' > Inf
# [1] TRUE

Error on 'If condition'-the condition has length > 1 and only the first element will be used [duplicate]

This question already has answers here:
Interpreting "condition has length > 1" warning from `if` function
(7 answers)
Closed 4 years ago.
in data frame ad2, if cost values is between upper & lower, then make a new data frame.
I tried the following:
if (ad2$Cost.x>=ad2$lower & ad2$Cost.x<=ad2$upper) {
ad3<-ad2[ad2$Country,ad2$Brand, ad2$Year, ad2$BU219.x, ad2$Cost.x, ad2$Value.x, ad2$Optimized_point.x]
}
but this error comes up
the condition has length > 1 and only the first element will be used
If you print the values of ad2$Cost.x>=ad2$lower & ad2$Cost.x<=ad2$upper, u can see more than one boolean conditions as a result. This is becuase in R all operations are vectorised.
Example:
> cc =c(T,F)
> if (cc) print(cc)
[1] TRUE FALSE
Warning message:
In if (cc) print(cc) :
the condition has length > 1 and only the first element will be used
So use all or any function like this :
> if (all(cc)) print(cc) #If all conditions are true
> if (any(cc)) print(cc)
[1] TRUE FALSE
Try this once
if (ad2$Cost.x>=ad2$lower & ad2$Cost.x<=ad2$upper) {
ad3 <- ad2[ , c(Country,Brand, Year, BU219.x, Cost.x, Value.x, Optimized_point.x)]
}

Dynamically numbering files in R with placeholders using an If-elseif

I have a vector
x <- c(1,90,233)
I need to convert this to a vector of the form:
result = c("001.csv","090.csv","233.csv")
This is the function that I wrote to perform this operation:
convert <- function(x){
for (a in 1:length(x)){
if (x[a]<10) {
x[a]<- paste("00",x[a],".csv",sep="")
}
else if (x[a] < 100) {
x[a]<- paste("0", x[a], ".csv",sep="")
}
else {
x[a]<-paste(x[a],".csv",sep="")
}
}
x
}
The output I got was:
[1] "001.csv","90.csv","233.csv"
So, a[2] is 90 was processed in the else part and not the else if part. Then I changed the else if condition to x[a]<=99
convert <- function(x){
for (a in 1:length(x)){
if (x[a]<10) {
x[a]<- paste("00",x[a],".csv",sep="")
}
else if (x[a] <= 99) {
x[a]<- paste("0", x[a], ".csv",sep="")
}
else {
x[a]<-paste(x[a],".csv",sep="")
}
}
x
}
I got this output:
[1] "001.csv" "090.csv" "0233.csv"
Now both x[2] and x[3] ie 90 and 233 are being processed in the ElseIf part. What am I doing wrong here? And how do I get the output I need?
This is a little bit more dynamic as you do not need to specify the number of places held by the largest number.
Step 1:
Obtain the maximum number of places held.
(nb = max(nchar(x)))
To get:
3
Step 2:
Paste the number into a sprintf() call that will automatically format the digit.
sprintf("%0*d.csv", nb, x)
To get:
[1] "001.csv" "090.csv" "233.csv"
The problem is that the first round of your loop makes a character, that converts the whole vector to type character. You can get around that using nchar
convert <- function(x){
for (a in 1:length(x)){
if (nchar(x[a]) == 1) {
x[a]<- paste("00",x[a],".csv",sep="")
}
else if (nchar(x[a]) == 2) {
x[a]<- paste("0", x[a], ".csv",sep="")
}
else {
x[a]<-paste(x[a],".csv",sep="")
}
}
x
}
sprintf("%03d", x)
[1] "001" "090" "233"
You can avoid a call to paste by including the ".csv" in the format string:
sprintf("%03d.csv", x)
[1] "001.csv" "090.csv" "233.csv"
The problem with the original code is the conversion to character, which happens on the first element.
Here's the conversion to character:
> x <- c(1, 90, 233)
> x
[1] 1 90 233
> x[1] <- "001.csv"
> x
[1] "001.csv" "90" "233"
Here's the resulting comparison of the second element:
> "90" <= 99
[1] TRUE
> "90" < 100
[1] FALSE
Similarly for the third:
> "233" < 100
[1] FALSE
> "233" <= 99
[1] TRUE
In all of these cases, the right-hand side is converted to character, then the comparison is made, as character strings.
Your code doesn't work as expected because the whole vector gets converted into a character vector after first assignment(conversion of numeric to character).
Please note that when a string is compared to digit, the characters are matched one by one. For eg. if you compare "90" to 100 then 9 is compared to 1, hence control goes to the else part and in the case of comparison of "233" to 99, 2 is compared 9.
You can get around this by assigning the changed values to another vector.Or, you could use the str_pad function from the stringr package.
library(stringr)
x=c(1,90,233)
padded_name= str_pad(x,width=3,side="left",pad="0")
file_name = paste0(padded_name, ".csv")

Resources