Concatenate number with string in Swift - string

I need to concatenate a String and Int as below:
let myVariable: Int = 8
return "first " + myVariable
But it does not compile, with the error:
Binary operator '+' cannot be applied to operands of type 'String' and 'Int'
What is the proper way to concatenate a String + Int?

If you want to put a number inside a string, you can just use String Interpolation:
return "first \(myVariable)"

You have TWO options;
return "first " + String(myVariable)
or
return "first \(myVariable)"

To add an Int to a String you can do:
return "first \(myVariable)"

If you're doing a lot of it, consider an operator to make it more readable:
func concat<T1, T2>(a: T1, b: T2) -> String {
return "\(a)" + "\(b)"
}
let c = concat("Horse ", "cart") // "Horse cart"
let d = concat("Horse ", 17) // "Horse 17"
let e = concat(19.2345, " horses") // "19.2345 horses"
let f = concat([1, 2, 4], " horses") // "[1, 2, 4] horses"
operator infix +++ {}
#infix func +++ <T1, T2>(a: T1, b: T2) -> String {
return concat(a, b)
}
let c1 = "Horse " +++ "cart"
let d1 = "Horse " +++ 17
let e1 = 19.2345 +++ " horses"
let f1 = [1, 2, 4] +++ " horses"
You can, of course, use any valid infix operator, not just +++.

Optional keyword would appear when you have marked variable as optional with ! during declaration.
To avoid Optional keyword in the print output, you have two options:
Mark the optional variable as non-optional. For this, you will have
to give default value.
Use force unwrap (!) symbol, next to variable
In your case, this would work just fine
return "first \(myVariable!)"

var a = 2
var b = "Hello W"
print("\(a) " + b)
will print 2 Hello W

Here is documentation about String and characters
var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"

Related

Have to count a character occurrence in Nim string type

How to count a character occurrence in string in Nim, mainly using its native statements prior go to module ? eg.
var
str = "Hello World"
c : int
c = numChar( "o", str ) # <- illustration only ?
The earlier answer is correct but if you do not want to import any modules you can write your own procedure:
proc count_char(value: string = "Hello World", ch: char = 'o'): int =
var cnt_c: int = 0
for c in value:
if c == ch:
cnt_c += 1
result = cnt_c
var
val: string = "Mother Goose"
ch: char = 'o'
echo $count_char(val, ch)
PS: Unrelated - Need syntax highlight for nim-lang on SO.
Use the count function from strutils:
import std/strutils
let str = "Hello World"
let count = count(str, 'o')
assert count = 1
There’s also a string overload for counting sub strings as well.

How can I concatenate multiple optional strings in swift 3.0?

I am trying to concatenate multiple strings in swift 3:
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = a! + b! + c!
When compiling I get the following error:
error: cannot convert value of type 'String' to specified type 'String?'
var d:String? = a! + b! + c!
~~~~~~~~^~~~
This used to work in swift 2. I am not sure why it doesn't work anymore.
Bug report filed by OP:
SR-1122: Failure to typecheck chain of binary operators on force-unwrapped values
Which has been resolved (fix commited to master Jan 3 2017), and should hence no longer be an issue in upcoming Swift 3.1.
This seems to be a bug (not present in Swift 2.2, only 3.0) associated with the case of:
Using the forced unwrapping operator (!) for at least 3 terms in an expression (tested using at least 2 basic operators, e.g. + or -).
For some reason, given the above, Swift messes up type inference of the expression (specifically, for the x! terms themselves, in the expression).
For all the examples below, let:
let a: String? = "a"
let b: String? = "b"
let c: String? = "c"
Bug present:
// example 1
a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 2
var d: String = a! + b! + c!
/* error: ambiguous reference to member '+' */
// example 3
var d: String? = a! + b! + c!
/* error: cannot convert value of type 'String'
to specified type 'String?' */
// example 4
var d: String?
d = a! + b! + c!
/* error: cannot assign value of type 'String'
to specified type 'String?' */
// example 5 (not just for type String and '+' operator)
let a: Int? = 1
let b: Int? = 2
let c: Int? = 3
var d: Int? = a! + b! + c!
/* error: cannot convert value of type 'Int'
to specified type 'Int?' */
var e: Int? = a! - b! - c! // same error
Bug not present:
/* example 1 */
var d: String? = a! + b!
/* example 2 */
let aa = a!
let bb = b!
let cc = c!
var d: String? = aa + bb + cc
var e: String = aa + bb + cc
/* example 3 */
var d: String? = String(a!) + String(b!) + String(c!)
However as this is Swift 3.0-dev, I'm uncertain if this is really a "bug", as well as what's the policy w.r.t. reporting "bugs" in a not-yet-production version of code, but possibly you should file radar for this, just in case.
As for answering your question as how to circumvent this issue:
use e.g. intermediate variables as in Bug not present: Example 2 above,
or explicitly tell Swift all terms in the 3-term expression are strings, as in Bug not present: Example 3 above,
or, better yet, use safe unwrapping of your optional, e.g. using optional binding:
var d: String? = nil
if let a = a, b = b, c = c {
d = a + b + c
} /* if any of a, b or c are 'nil', d will remain as 'nil';
otherwise, the concenation of their unwrapped values */
Swift 3
let q: String? = "Hello"
let w: String? = "World"
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// HelloWorld!
let q: String? = "Hello"
let w: String? = nil
let r: String? = "!"
var array = [q, w, r]
print(array.flatMap { $0 }.reduce("", {$0 + $1}))
// Hello!
func getSingleValue(_ value: String?..., seperator: String = " ") -> String? {
return value.reduce("") {
($0) + seperator + ($1 ?? "")
}.trimmingCharacters(in: CharacterSet(charactersIn: seperator) )
}
let val: String? = "nil"
val.flatMap({(str: String) -> String? in
return str + "value"
})
var a:String? = "a"
var b:String? = "b"
var c:String? = "c"
var d:String? = ""
let arr = [a,b,c]
arr.compactMap { $0 }.joined(separator: " ")
compactMap be used to filter out nil values from flattened arrays

Divide Swift String into groups of 3 symbols

I'm making a formatter for currency string, for example I have Int:
let a: Int = 10
let b: Int = 10000
let c: Int = 10000000
I want them to be formatted like:
let a1:String = "10"
let b1:String = "10 000"
let c1:String = "10 000 000"
So I need funtion (or extension) in Swift as elegant, as you can suggest =) You have a Int as input parameter and you should output it as a String with " "(space symbol) every 3 symbols from right to left.
this may help you :
func formatNumberString(number : String?) -> String?
{
//"10 000 000 M"
// 01234567890123 -> 2,6,10
if (number?.isEmpty == true || number?.length <= 2) {
return number
}
var i : Int = 0
var newNumber : String = ""
for character in (number?.characters)! {
if ((i == 2 || i == 6 || i == 10) && character != " ")
{
newNumber = newNumber + " "
}
i++
}
return newNumber
}
You should user NSNumberFormatter to format your number:
func numberToCurrency(number: Int) -> String {
let formatter: NSNumberFormatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.positiveSuffix = " M"
formatter.currencySymbol = ""
formatter.maximumFractionDigits = 0
formatter.currencyGroupingSeparator = " "
formatter.usesGroupingSeparator = true
return formatter.stringFromNumber(number)!
}
print(numberToCurrency(1000)) will print 1 000 M. If you don't want to show M character, just set formatter.positiveSuffix = ""
You can use this as extension and just call if input is string
let requiredN = "10000000".convertToFormat()
this is the extension for string
extension String
{
func convertToFormat() -> String
{
return (NSNumberFormatter.localizedStringFromNumber(Int(self)!, numberStyle: NSNumberFormatterStyle.DecimalStyle) as String).stringByReplacingOccurrencesOfString(",", withString: " ")
}
}
If input value is Int call
let requiredN = 10000000.convertToFormat()
and extension for Int
extension Int
{
func convertToFormat() -> String
{
return (NSNumberFormatter.localizedStringFromNumber(self, numberStyle: NSNumberFormatterStyle.DecimalStyle) as String).stringByReplacingOccurrencesOfString(",", withString: " ")
}
}

Swift REPL Unexpected Behaviour

If I use the following code in Swift repl, I get unexpected results:
1> func addA(s: String)->String {
2. return s + "a"
3. }
4.
5. func addB(s: String)->String {
6. return s + "b"
7. }
8>
9> println(addA(""))
a
10> println(addB(""))
b
11> println(addA(addB("")))
ba
12> let p = addA(addB(""))
p: ((String)) = {
_core = {
_baseAddress = 0x0000000100500060
_countAndFlags = 2
_owner = (instance_type = Builtin.RawPointer = 0x0000000100500040)
}
}
13> println(p)
ba
14> let q = "a" + "b"
q: String = "ab"
why does declaring p produce this behaviour, while declaring q does not?
All that's happening here is that the REPL is letting you look inside Swift at some of the underlying efficiencies. p is stored as some sort of function composition. When evaluation is needed, it is evaluated. If you didn't want to see the sausage being made, you should not have entered the sausage factory.

Use character string as function argument

I'm sure this is simple, but I cannot find a solution ...
I would like to use a variable containing a character string as argument for a function.
x <- c(1:10)
myoptions <- "trim=0, na.rm=FALSE"
Now, something like
foo <- mean(x, myoptions)
should be the same as
foo <- mean(x, trim=0, na.rm=FALSE)
Thanks in advance!
You can use eval and parse:
foo <- eval(parse(text = paste("mean(x,", myoptions, ")")))
A more natural way to do what you want is to use do.call. For example,
R> l[["trim"]] = 0
R> l[["na.rm"]] = FALSE
R> l[["x"]] = 1:10
##Or l <- list(trim = 0, na.rm = FALSE, x = 1:10)
R> do.call(mean, l)
[1] 5.5
If for some reason you really want to use a myoptions string, you could always use strsplit to coarce it into a list form. For example,
R> y = "trim=0, na.rm=FALSE"
R> strsplit(y, ", ")
[[1]]
[1] "trim=0" "na.rm=FALSE"
R> strsplit(y, ", ")[[1]][1]
[1] "trim=0"
Here's a third answer that both uses parse, alist and do.call. My motivation for this new answer, is in the case where arguments are passed interactively from a client-side as chars. Then I guess, there is no good way around not using parse. Suggested solution with strsplit, cannot understand the context whether a comma , means next argument or next argument within an argument. strsplit does not understand context as strsplit is not a parser.
here arguments can be passed as "a=c(2,4), b=3,5" or list("c(a=(2,4)","b=3","5")
#' convert and evaluate a list of char args to a list of arguments
#'
#' #param listOfCharArgs a list of chars
#'
#' #return
#' #export
#'
#' #examples
#' myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
#' myArgs = callMeMaybe(myCharArgs)
#' do.call(mean,myArgs)
callMeMaybe2 = function(listOfCharArgs) {
CharArgs = unlist(listOfCharArgs)
if(is.null(CharArgs)) return(alist())
.out = eval(parse(text = paste0("alist(",
paste(parse(text=CharArgs),collapse = ","),")")))
}
myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
myArgs = callMeMaybe2(myCharArgs)
do.call(mean,myArgs)
[1] 2
Using all of do.call, eval and parse (combining kohske's and csgillespie's answers, and also WoDoSc's answer to 'Pass a comma separated string as a list'):
x <- c(1:10)
myoptions <- "trim = 0, na.rm = FALSE"
do.call(
what = mean,
args = append(list(x = x), eval(parse(text = paste0("list(", myoptions, ")"))))
)
This solution can be quite resilient in a more complex case, such as shown below.
myfn <- function(x, y = 0, z = 0, ...) {
print(paste("x:", x))
print(paste("y:", y))
print(paste("z:", z))
if (length(list(...)) > 0) {
print("other:")
print(list(...))
}
}
myextraargs <- paste(
"y = c(11, 14), z = 47,",
"t = data.frame(p = c('apple', 'plum'), j = c(7, 2), k = c(3, 21))"
)
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in:
[1] "x: 7"
[1] "y: 11" "y: 14"
[1] "z: 47"
[1] "other:"
$t
p j k
1 apple 7 3
2 plum 2 21
...and...
myextraargs <- NULL
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in
[1] "x: 7"
[1] "y: 0"
[1] "z: 0"

Resources