what I am trying to accomplish is as follows:
I am trying to have an expression that returns a value "A" if 'apple' is anywhere in the string, and return value "B" if 'bell' is anywhere in the string.
if 'apple' or 'bell' is not in the string, then 'null'
eg, the column will have 'apple', 'bell', 'any other word' at different positions in the string and I need a formula that returns "A" if 'apple' in present and "B" if 'bell' is present
column value example:
'applebee'
'appletart'
'bellview'
'bellmont'
'apple fritter'
'freedom bell'
'bird'
'coffin'
'...'
desired outcome:
"A"
"A"
"B"
"B"
"A"
"B"
"null"
"null"
"null"
i have tried:
[description] contains 'INV' then 1
[description] contains 'VOL' then 2
else 'null'
maybe an if statement could work better?
What happens when you try:
if(lower([description]) contains 'apple') then ('A') else
if (lower([description]) contains 'bell') then ('B') else
(Null)
In TCL, there is an array var defined.
set array_var(a1) "this is a string, not list"
set array_var(a2) [list a b c d e]
set array_var(a3) [list { "aa" "bb" } { "bb" "cc" }]
I want to write out array_var definition which can be source back later.
foreach key [array names array_var] {
set nameString [format %s(%s) array_var $key]
puts $SI_fh "set $nameString \"$array_var($key)\""
}
How to generate output file just as original definition with and without "[list "?
set array_var(a1) "this is a string, not list"
set array_var(a2) [list a b c d e]
set array_var(a3) [list { "aa" "bb" } { "bb" "cc" }]
parray array_var
prints
array_var(a1) = this is a string, not list
array_var(a2) = a b c d e
array_var(a3) = { "aa" "bb" } { "bb" "cc" }
At this point, you can't go back and see how these values were created: the array elements contain just the values, not the history.
There are many ways to create these values:
list "this" "is" "a" "string," "not" "list"
string cat this " " is " " a " " string ", " not " " list
dict create this is a string, not list
And a string with an even number of space separated words is indistinguishable from a list with an even number of elements, or a dictionary value.
for storing the state of this array, I'd do
foreach {key value} [array get array_var] {
puts [list set "array_var($key)" $value]
}
set array_var(a3) {{ "aa" "bb" } { "bb" "cc" }}
set array_var(a1) {this is a string, not list}
set array_var(a2) {a b c d e}
If you want to store an array for later, and are not particularly bothered about the stored format being very readable, the simplest method is this (yes, sourceing the file is how to load it back in):
puts $SI_fh [list array set array_var [array get array_var]]
The array get command serializes an array (without any traces, but that's usually not a problem at all) and array set takes the serialized form (which is a dictionary) and reinflates it back into an array. The list is because that creates exactly the quoting we want to make a substitution-free command (it's how the format of lists is defined to work).
The only disadvantage is that the format actually in the file is not optimised for humans, being something like this (the actual order is arbitrary; Tcl's arrays have never made order guarantees):
array set array_var {a2 {a b c d e} a1 {this is a string, not list} a3 {{ "aa" "bb" } { "bb" "cc" }}}
I'm currently using Crystal Reports 2013 to run reports. I'm having an issue with a formula that needs to look at an SAP order status and only print out a specific few. The SAP Order Status field is made up of 2 sections.
Section 1: 'A' 'B' 'C' 'D' (Only a single selection is pulled from
this list)
Section 2: 'E' 'F' 'G' 'H' (This can have multiple selections within
the Status)
Example Order #1111 Status: "A: F: G"
I currently have a formula that pulls the status of an order from the 1st Section.
if (isnull({user_status}) or
{user_status}=" " or
not ({user_status} like ["*A*", "*B*", "*C*", "*D*"])) then "N/A" else
if {user_status} like "*A*" then "A" else
if {user_status} like "*B*" then "B" else
if {user_status} like "*C*" then "C" else
if {user_status} like "*D*" then "D"
The above snippet would only bring in "A" for Order #1111 and omit "F" & "G".
I need assistance with a formula that would omit "A" and list out both "F" & "G".
I've tried the following:
if (isnull({user_status}) or
{user_status}=" " or
not ({user_status} like ["*E*", "*F*", "*G*", "*H*"])) then "N/A" else
if {user_status} like "*E*" then "E" else
if {user_status} like "*F*" then "F" else
if {user_status} like "*G*" then "G" else
if {user_status} like "*H*" then "H"
But that formula just returns the full "A; F; G" status.
Figured out the answer. (6/9/2020) I used the following code to create an array and loop through it pulling out only what I needed.
NumberVar Counter;
StringVar finalStatus:= "";
StringVar array statusList;
statusList:= split({user_status},";");
//Loop through array and only print out Status w/o No values
FOR Counter := 1 to UBound(statusList) DO
(if statusList[Counter] like ["E", "F", "G", "H"] then
finalStatus:= finalStatus+statusList[Counter]+";" else "");
finalStatus
Thanks for the input.
Take the following code to select only alphanumeric strings from a list of strings:
isValid = function(string){
return(grep("^[A-z0-9]+$", string))
}
strings = c("aaa", "test#test.com", "", "valid")
print(Filter(isValid, strings))
The output is [1] "aaa" "test#test.com".
Why is "valid" not outputted, and why is "test#test.com" outputted?
The Filter function accepts a logical vector, you supplied a numeric. Use grepl:
isValid = function(string){
return(grepl("^[A-z0-9]+$", string))
}
strings = c("aaa", "test#test.com", "", "valid")
print(Filter(isValid, strings))
[1] "aaa" "valid"
Why didn't grep work? It is due to R's coercion of numeric values to logical and the weirdness of Filter.
Here's what happened, grep("^[A-z0-9]+$", string) correctly returns 1 4. That is the index of matches on the first and fourth elements.
But that is not how Filter works. It runs the condition on each element with as.logical(unlist(lapply(x, f))).
So it ran isValid(strings[1]) then isValid(strings[2]) and so on. It created this:
[[1]]
[1] 1
[[2]]
integer(0)
[[3]]
integer(0)
[[4]]
[1] 1
It then called unlist on that list to get 1 1 and turned that into a logical vector TRUE TRUE. So in the end you got:
strings[which(c(TRUE, TRUE))]
which turned into
strings[c(1,2)]
[1] "aaa" "test#test.com"
Moral of the story, don't use Filter :)
You could go the opposite direction with this and exclude any strings with punctuation, i.e.
isValid <- function(string){
v1 <- string[!string %in% grep('[[:punct:]]', string, value = TRUE)]
return(v1[v1 != ''])
}
isValid(strings)
#[1] "aaa" "valid"
I have a series of column names that I'm trying to standardize.
names <- c("apple", "banana", "orange", "apple1", "apple2", "apple10", "apple11", "banana2", "banana12")
I would like anything that has a one digit number to be padded by a zero, so
apple
banana
orange
apple01
apple02
apple10
apple11
banana02
...
I've been trying to use stringr
strdouble <- str_detect(names, "[0-9]{2}")
strsingle <- str_detect(names, "[0-9]")
str_detect(names[strsingle & !strdouble])
but unable to figure out how to selectively replace/prepend...
You can use sub("([a-z])([0-9])$","\\10\\2",names) :
[1] "apple" "banana" "orange" "apple01" "apple02" "apple10" "apple11" "banana02"
[9] "banana12"
It only changes the names where there is a single digit following a letter (the $ is the end of the string).
The \\1 selects the first block in () : the letter. Then it puts a leading 0, then the second block in () : the digit.
Here's one option using negative look-ahead and look-behind assertions to identify single digits.
gsub('(?<!\\d)(\\d)(?!\\d)', '0\\1', names, perl=TRUE)
# [1] "apple" "banana" "orange" "apple01" "apple02" "apple10" "apple11" "banana02" "banana12"
str_pad from stringr:
library(stringr)
pad_if = function(x, cond, n, fill = "0") str_pad(x, n*cond, pad = fill)
s = str_split_fixed(names,"(?=\\d)",2)
# [,1] [,2]
# [1,] "apple" ""
# [2,] "banana" ""
# [3,] "orange" ""
# [4,] "apple" "1"
# [5,] "apple" "2"
# [6,] "apple" "10"
# [7,] "apple" "11"
# [8,] "banana" "2"
# [9,] "banana" "12"
paste0(s[,1], pad_if(s[,2], cond = nchar(s[,2]) > 0, n = max(nchar(s[,2]))))
# [1] "apple" "banana" "orange" "apple01" "apple02" "apple10" "apple11" "banana02" "banana12"
This also extends to cases like going from c("a","a2","a20","a202") to c("a","a002","a020","a202"), which the other approaches don't cover.
The stringr package is based on stringi, which has all the same functionality used here, I'm guessing.
sprintf from base, with a similar approach:
pad_if2 = function(x, cond, n, fill = "0")
replace(x, cond, sprintf(paste0("%",fill,n,"d"), as.numeric(x)[cond]))
s0 = strsplit(names,"(?<=\\D)(?=\\d)|$",perl=TRUE)
s1 = sapply(s0,`[`,1)
s2 = sapply(sapply(s0,`[`,-1), paste0, "")
paste0(s1, pad_if2(s2, cond = nchar(s2) > 0, n = max(nchar(s2))))
pad_if2 has less general use than pad_if, since it requires x be coercible to numeric. Pretty much every step here is clunkier than the corresponding code with the packages mentioned above.
Key is to identify single digit with $ and letter before digit. It could be tried:
gsub('[^0-9]([0-9])$','0\\1',names)
[1] "apple" "banana" "orange" "appl01" "appl02" "apple10" "apple11" "banan02" "banana12"
or look-ahead.
gsub('(?<=[a-z])(\\d)$','0\\1',names,perl=T)