As of right now i retrieve the first item in my list that i generate by using split, but i also want the last item in a seperate function.
The problem ist the list is generated from an ocr and is never the same length or size.
is there a way in kotlin to always get the last item?
This is the code for getting the first :
fun String.firstLine(): String {
if (this.isEmpty()) return ""
return this.split("\n").get(0)
}
You can do something like this:
fun String.firstAndLast() = split("\n").let { it.first() to it.last() }
fun main() {
val s = "first line\nsecond line\nlast line"
val (first, last) = s.firstAndLast()
println(first)
println(last)
}
output is:
first line
last line
The fun will split, then use the resulting list and get only the first and last element, returning a Pair<String, String>, which can be easily deconstructed with val (first, last), then those values can be used separately.
Edit: for the penultimate as well, I don't think that a list might be a good idea. I personally would go with an object of sorts, or with a Triple.
Class way:
class NoNameIdeas(
val first: String = "",
val penultimate: String = "",
val last: String = ""
) {
companion object {
fun fromString(string: String): NoNameIdeas {
val l = string.split("\n")
val first = l.first()
return when (l.size) {
1 -> NoNameIdeas(first = first)
2 -> NoNameIdeas(first = first, penultimate = "what should this be?", last = l.last())
else -> NoNameIdeas(first = first, penultimate = l[l.lastIndex - 1], last = l.last())
}
}
}
}
fun main() {
val string = "first line\nsecond line\nsecond last\nlast line"
val result = NoNameIdeas.fromString(string)
println(result.first)
println(result.penultimate)
println(result.last)
}
As you can guess, I have no idea how to name this object. Another issues is, what should we do with the penultimate, if we only have 2 lines in total? It can be the same as the first, or it can be empty, or it can be the same as the last. That is your decision, it also might never happen, only you know what data you have.
Another way of doing it without a class, but by using a triple:
Triple way:
fun main() {
val string = "first line\nsecond line\nsecond last\nlast line"
val result = string.firstPenultimateAndLast()
println(result.first)
println(result.second)
println(result.third)
}
fun String.firstPenultimateAndLast(): Triple<String, String, String> {
val l = split("\n")
val first = l.first()
var penultimate = "" //same as the class, what happens when we only have 2 lines?
var last = l.first() //if we only have 1, then I guess that the first is the last as well, will get a new value otherwise
when (l.size) {
2 -> last = l.last()
else -> {
penultimate = l[lastIndex - 1]
last = l.last()
}
}
return Triple(first, penultimate, last)
}
I'm reading a text file and have the syntax set up correctly to do so. What I want to do now is append all the integers into an array, but when I try to use a print statement to check what's going on, nothing shows up in the terminal.
package lecture
import scala.io.{BufferedSource, Source}
object LectureQuestion {
def fileSum(fileName: String): Int = {
var arrayOfnumbers = Array[String]()
var fileOfnumbers: BufferedSource = Source.fromFile(fileName)
for (line <- fileOfnumbers.getLines()){
val splits: Array[String] =line.split("#")
for (number <- splits){
arrayOfnumbers :+ number
println(arrayOfnumbers.mkString(""))
}
//println(splits.mkString(" "))
}
3
}
def main(args: Array[String]): Unit = {
println(fileSum("data/fileOfnumbers.txt"))
}
}
I set up a blank array to append the numbers to. I tried switching var to val, but that wouldn't make sense as var is mutuable, meaning it can change. I'm pretty sure the way to add things to an array in Scala is :+, so I'm not sure what's going on.
In Scala all you would need is flatMap the List of a List and then sum the result.
Here your example simplified, as we have extracted the lines already:
import scala.util.Try
def listSum(lines: List[String]): Int = {
(for{
line <- lines
number <- line.split("#").map(n => Try(n.trim.toInt).getOrElse(0))
} yield number).sum
}
listSum(List("12#43#134#bad","13#54#47")) // -> 303
No vars, resp. no mutability needed. Just a nice for-comprehension;).
And for comparison the solution with flatMap:
def listSum(lines: List[String]): Int = {
lines
.flatMap(_.split("#").map(n => Try(n.trim.toInt).getOrElse(0)))
.sum
}
I want to use arc4random to generate array of 30 different numbers, so that there is no repeating in it. How can I do it?
Update:
Thanks to #Sulthan for his elegant thought (commented on Gereon's answer):
anyway, depending on the difference between limit and the number of
generated elements this can have a terrible performance. The problem
is the case when limit is close to the number of generated elements.
Then it would be much better to take 1..<limit and shuffle it.
Which means that there is no even need to generate random Int. The simplest way I could think of is to do it as (Swift 4.2):
let randoms = Array(0..<30).shuffled()
therefore randoms is an array of Ints, contains 30 unique values from 0 to 29.
Less Than Swift 4.2:
However, if you are not using Swift 4.2, I would recommend to check this great answer for getting shuffled collection.
Ignored Solution:
You could achieve it like this:
var uniques = Set<UInt32>()
func generateUniqueUInt32() -> UInt32 {
let random = arc4random_uniform(31)
if !uniques.contains(random) {
uniques.insert(random)
return random
} else {
return generateUniqueUInt32()
}
}
let randomArray = Array(0..<30).map { _ in Int(generateUniqueUInt32()) }
Therefore randomArray is an array of Ints, contains 30 unique values from 0 to 29.
Swift 4.2:
You should replace:
let random = arc4random_uniform(31)
with:
let random = Int.random(in: 1..<30)
which means that generateUniqueUInt32 should return -directly- Int (and renamed to generateUniqueInt):
func generateUniqueInt() -> Int {
let random = Int.random(in: 1..<30)
if !uniques.contains(random) {
uniques.insert(random)
return random
} else {
return generateUniqueInt()
}
}
let randomArray = Array(0..<30).map { _ in generateUniqueInt() }
It may be a pretty heavy action but you can do like that:
var randomNumbers: [Int] = []
while randomNumbers.count != 30{
let number = Int(arc4random_uniform(1000) + 1)
if randomNumbers.contains(number) {
print("Already Exits")
}else{
randomNumbers.append(number)
}
}
replace "1000" for a range of number that you need. That function generated 30 different number between 0...1000
Use a Set to store the generated numbers so far
func thirtyUniqueRandomNumbers(_ limit: Int) -> [Int] {
var randoms = Set<Int>()
repeat {
let rnd = Int(arc4random_uniform(UInt32(limit)))
if !randoms.contains(rnd) {
randoms.insert(rnd)
}
} while randoms.count < 30
return randoms.map { $0 }
}
Here is a simple solution. Start a while loop. Within this loop generate a random number (between 0 and 1000). And then append the number into your array if the array doesn't contains the number.
func generateArrayOfRandomNumbers() -> [Int] {
var array: [Int] = []
while array.count < 30 {
let randomInt = Int.random(in: 0...1000)
guard !array.contains(randomInt) else { continue }
array.append(randomInt)
}
return array
}
How to concatenate string in Swift?
In Objective-C we do like
NSString *string = #"Swift";
NSString *resultStr = [string stringByAppendingString:#" is a new Programming Language"];
or
NSString *resultStr=[NSString stringWithFormat:#"%# is a new Programming Language",string];
But I want to do this in Swift-language.
You can concatenate strings a number of ways:
let a = "Hello"
let b = "World"
let first = a + ", " + b
let second = "\(a), \(b)"
You could also do:
var c = "Hello"
c += ", World"
I'm sure there are more ways too.
Bit of description
let creates a constant. (sort of like an NSString). You can't change its value once you have set it. You can still add it to other things and create new variables though.
var creates a variable. (sort of like NSMutableString) so you can change the value of it. But this has been answered several times on Stack Overflow, (see difference between let and var).
Note
In reality let and var are very different from NSString and NSMutableString but it helps the analogy.
You can add a string in these ways:
str += ""
str = str + ""
str = str + str2
str = "" + ""
str = "\(variable)"
str = str + "\(variable)"
I think I named them all.
var language = "Swift"
var resultStr = "\(language) is a new programming language"
This will work too:
var string = "swift"
var resultStr = string + " is a new Programming Language"
\ this is being used to append one string to another string.
var first = "Hi"
var combineStr = "\(first) Start develop app for swift"
You can try this also:- + keyword.
var first = "Hi"
var combineStr = "+(first) Start develop app for swift"
Try this code.
let the_string = "Swift"
let resultString = "\(the_string) is a new Programming Language"
Very Simple:
let StringA = "Hello"
let StringB = "World"
let ResultString = "\(StringA)\(StringB)"
println("Concatenated result = \(ResultString)")
You can now use stringByAppendingString in Swift.
var string = "Swift"
var resultString = string.stringByAppendingString(" is new Programming Language")
Xcode didn't accept optional strings added with a normal string. I wrote this extensions to solve that problem:
extension String {
mutating func addString(str: String) {
self = self + str
}
}
Then you can call it like:
var str1: String?
var str1 = "hi"
var str2 = " my name is"
str1.addString(str2)
println(str1) //hi my name is
However you could now also do something like this:
var str1: String?
var str1 = "hi"
var str2 = " my name is"
str1! += str2
It is called as String Interpolation.
It is way of creating NEW string with CONSTANTS, VARIABLE, LITERALS and EXPRESSIONS.
for examples:
let price = 3
let staringValue = "The price of \(price) mangoes is equal to \(price*price) "
also
let string1 = "anil"
let string2 = "gupta"
let fullName = string1 + string2 // fullName is equal to "anilgupta"
or
let fullName = "\(string1)\(string2)" // fullName is equal to "anilgupta"
it also mean as concatenating string values.
Hope this helps you.
I just switched from Objective-C to Swift (4), and I find that I often use:
let allWords = String(format:"%# %# %#",message.body!, message.subject!, message.senderName!)
Swift 5
You can achieve it using appending API. This returns a new string made by appending a given string to the receiver.
API Details : here
Use:
var text = "Hello"
text = text.appending(" Namaste")
Result:
Hello
Hello Namaste
To print the combined string using
Println("\(string1)\(string2)")
or String3 stores the output of combination of 2 strings
let strin3 = "\(string1)\(string2)"
One can also use stringByAppendingFormat in Swift.
var finalString : NSString = NSString(string: "Hello")
finalString = finalString.stringByAppendingFormat("%#", " World")
print(finalString) //Output:- Hello World
finalString = finalString.stringByAppendingFormat("%#", " Of People")
print(finalString) //Output:- Hello World Of People
Concatenation refers to the combining of Strings in Swift. Strings may contain texts, integers, or even emojis! There are many ways to String Concatenation. Let me enumerate some:
Same String
Using +=
This is useful if we want to add to an already existing String. For this to work, our String should be mutable or can be modified, thus declaring it as a Variable. For instance:
var myClassmates = "John, Jane"
myClassmates += ", Mark" // add a new Classmate
// Result: "John, Jane, Mark"
Different Strings
If we want to combine different Strings together, for instance:
let oldClassmates = "John, Jane"
let newClassmate = "Mark"
We can use any of the following:
1) Using +
let myClassmates = oldClassmates + ", " + newClassmate
// Result: "John, Jane, Mark"
Notice that the each String may be a Variable or a Constant. Declare it as a Constant if you're only gonna change the value once.
2) String Interpolation
let myClassmates = "\(oldClassmates), \(newClassmate)"
// Result: "John, Jane, Mark"
3) Appending
let myClassmates = oldClassmates.appending(newClassmate)
// Result: "John, Jane, Mark"
Refer to Strings & Characters from the Swift Book for more.
Update: Tested on Swift 5.1
Swift 4.2
You can also use an extension:
extension Array where Element == String? {
func compactConcate(separator: String) -> String {
return self.compactMap {
if let unwrappedString = $0,
unwrappedString.isEmpty {
return nil
} else {
return $0
}
}
.joined(separator: separator)
}
}
Use:
label.text = [m.firstName, m.lastName].compactConcate(separator: " ")
Result:
"The Man"
"The"
"Man"
From: Matt Neuburg Book “iOS 13 Programming Fundamentals with Swift.” :
To combine (concatenate) two strings, the simplest approach is to use the + operator:
let s = "hello"
let s2 = " world"
let greeting = s + s2
This convenient notation is possible because the + operator is overloaded: it does one thing when the operands are numbers (numeric addition) and another when the operands are strings (concatenation).
The + operator comes with a += assignment shortcut; naturally, the variable on the left side must have been declared with var:
var s = "hello"
let s2 = " world"
s += s2
As an alternative to +=, you can call the append(_:) instance method:
var s = "hello"
let s2 = " world"
s.append(s2)
Another way of concatenating strings is with the joined(separator:) method. You start with an array of strings to be concatenated, and hand it the string that is to be inserted between all of them:
let s = "hello"
let s2 = "world"
let space = " "
let greeting = [s,s2].joined(separator:space)
Swift 5:
Array of strings into a Single string
let array = ["Ramana","Meharshi","Awareness","Oneness","Enlightnment","Nothing"]
let joined = array.joined(separator: ",")
Swift concatenate strings
Several words about performance
UI Testing Bundle on iPhone 7(real device), iOS 14, -Onone(debug, without optimizations)[About]
var result = ""
for i in 0...count {
<concat_operation>
}
Count = 5_000
//Append
result.append(String(i)) //0.007s 39.322kB
//Plus Equal
result += String(i) //0.006s 19.661kB
//Plus
result = result + String(i) //0.130s 36.045kB
//Interpolation
result = "\(result)\(i)" //0.164s 16.384kB
//NSString
result = NSString(format: "%#%i", result, i) //0.354s 108.142kB
//NSMutableString
result.append(String(i)) //0.008s 19.661kB
Disable next tests:
Plus up to 100_000 ~10s
interpolation up to 100_000 ~10s
NSString up to 10_000 -> memory issues
Count = 1_000_000
//Append
result.append(String(i)) //0.566s 5894.979kB
//Plus Equal
result += String(i) //0.570s 5894.979kB
//NSMutableString
result.append(String(i)) //0.751s 5891.694kB
*Note about Convert Int to String
Source code
import XCTest
class StringTests: XCTestCase {
let count = 1_000_000
let metrics: [XCTMetric] = [
XCTClockMetric(),
XCTMemoryMetric()
]
let measureOptions = XCTMeasureOptions.default
override func setUp() {
measureOptions.iterationCount = 5
}
func testAppend() {
var result = ""
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result.append(String(i))
}
}
}
func testPlusEqual() {
var result = ""
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result += String(i)
}
}
}
func testPlus() {
var result = ""
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result = result + String(i)
}
}
}
func testInterpolation() {
var result = ""
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result = "\(result)\(i)"
}
}
}
//Up to 10_000
func testNSString() {
var result: NSString = ""
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result = NSString(format: "%#%i", result, i)
}
}
}
func testNSMutableString() {
let result = NSMutableString()
measure(metrics: metrics, options: measureOptions) {
for i in 0...count {
result.append(String(i))
}
}
}
}
You could use SwiftString (https://github.com/amayne/SwiftString) to do this.
"".join(["string1", "string2", "string3"]) // "string1string2string"
" ".join(["hello", "world"]) // "hello world"
DISCLAIMER: I wrote this extension
In Swift 5 apple has introduces Raw Strings using # symbols.
Example:
print(#"My name is "XXX" and I'm "28"."#)
let name = "XXX"
print(#"My name is \#(name)."#)
symbol # is necessary after \. A regular \(name) will be interpreted as characters in the string.
What I want to do is be able to compare a number with a range of numbers, here I'm using a dictionary of arrays because is the only thing I can think of, but it could literately be anything.
In theory this is what I want is psudo code...
myNumber
rangeOne
rangeTwo
rangeThree
Does myNumber fit in any of the range numbers? If yes in which one?
Here is what I have been playing with which kind of tells me whether it fits or not but it doesn't tell me in which range it did fit.
var myNumber = 72
let rangeNumbers = [
"rangeOne": [72,104],
"rangeTwo": [60,88],
"rangeThree": [80,150],
]
for (rangeName, range) in rangeNumbers {
for number in range {
if myNumber <= number {
print(number)
print(rangeName)
print("It's smaller/equal than \(myNumber)")
print("-------------------------")
break
}else{
print(number)
print(rangeName)
print("It's bigger than \(myNumber)")
print("-------------------------")
break
}
}
}
What would be the best way to compare a number with a range-number and know in what range did the number fit?
Thanks
I would rather do something like that:
for (rangeName, range) in rangeNumbers {
if range.count > 1
{
if myNumber >= range.first! && myNumber <= range.last! {
print(rangeName)
}
}
}
That will work if your range array will contain only two elements min and max.
But better way would be use Range.
Time for some fun in swift, here is the one liner:
let rangeIndex = rangeNumbers.indexOf{ $0.1.first <= myNumber && $0.1.last >= myNumber }
Then you can use it like:
print(rangeNumbers[rangeIndex!])
use Range instead ..
let range: Range<Int> = Range(start: 1,end: 100)
range.contains(10) // true
... in your example
var myNumber = 72
let rangeNumbers = [
"rangeOne": [72,104],
"rangeTwo": [60,88],
"rangeThree": [80,150],
]
let result = rangeNumbers.flatMap { (d) -> String? in
let range: Range<Int> = Range(start: d.1[0],end: d.1[1] + 1)
return range.contains(myNumber) ? d.0 : nil
}
print(result) // ["rangeOne", "rangeTwo"]
myNumber = 720
let result2 = rangeNumbers.flatMap { (d) -> String? in
let range: Range<Int> = Range(start: d.1[0],end: d.1[1] + 1)
return range.contains(myNumber) ? d.0 : nil
}
print(result2) // []
for safety, first check your dictionary ..