Swift 4, how to remove two nth charterers from sentence, and start counting each letter in sentence from 1 instead of 0 - swift

I've come outwith this code to remove two charahcters from sentence, however I was wondering how to start counting sentence from 1 when removing characters.
Examplre user enters in each textfield as following:
textfield.text: Hi, thankyou
inputlabelOne.text: 2
inputLabelTwo.text: 5
My code:
var numberOne = Int (InputLabelOne.text)!
var numberTwo = Int (InputLabelTwo.text)!
var text = textfield.text!
var num1 = numberOne
var num2 = numberTwo
if let oneIndex = text.index ((text.startIndex), offsetBy:
num1, limetedBy:(text.endIndex)) ,
let twoIndex = text.index ((text.startIndex), offsetBy: num2,
limetedBy:(text.endIndex)) {
text.remove(at: oneIndex)
text.remove(at: twoIndex)
outputLabel.Text = "sentence with removed letters: \(text)"
}

Firstly, you need to get first index of the string
let startIndex = string.startIndex
Next, you need to get String.Index of the character at first position
let index1 = string.index(startIndex, offsetBy: num1 - 1)
I type minus one because first character has 0 index
Next, you can remove this character
str.remove(at: index1)
Same for the second character
let offset = num1 > num2 ? 1 : 2
let index2 = string.index(startIndex, offsetBy: num2 - offset)
str.remove(at: index2)
If num1 is less than num2 then offset value is 2 because we have already removed one character.
If num1 is greater than num2 then offset value is 1 as for num1.

To avoid the mutating while iterating mistake you have to remove the characters backwards starting at the highest index.
To get 1-based indices just subtract 1 from the offset respectively
var text = "Hi, thankyou"
let inputLabelOne = 2
let inputLabelTwo = 5
if let oneIndex = text.index(text.startIndex, offsetBy: inputLabelOne - 1, limitedBy: text.endIndex),
let twoIndex = text.index(text.startIndex, offsetBy: inputLabelTwo - 1, limitedBy: text.endIndex) {
text.remove(at: twoIndex)
text.remove(at: oneIndex)
}
print(text) // H, hankyou
or as function
func remove(at indices: [Int], from text: inout String) {
let sortedIndices = indices.sorted(by: >)
for index in sortedIndices {
if let anIndex = text.index(text.startIndex, offsetBy: index - 1, limitedBy: text.endIndex) {
text.remove(at: anIndex)
}
}
}
remove(at: [inputLabelOne, inputLabelTwo], from: &text)

Related

return "location" of variable in a string

This is a bit on an odd ball question and I am not sure if it is possible to do, none the less.
I am trying to identify the "count" position of an item within a string.
For instance if I have a string: "hello what a lovely day" (23 characters) and I would like to know where in the sting the spaces are. In this case the sting would have a space at the 6th, 11th, 13th and 20th characters. Is there a function that would provide this feedback?
Any insight would be appreciated.
Thank you in advance for your valued time and insight.
Try this extension:
extension String {
func indicesOf(string: String) -> [Int] {
var indices = [Int]()
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.range(of: string, range: searchStartIndex..<self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
}
Usage (note that in Swift, nth characters start at 0 and not 1):
let string = "hello what a lovely day"
let indices = string.indicesOf(string: " ")
print("Indices are \(indices)")
Indices are [5, 10, 12, 19]

Split a large [MLMultiArray] into smaller chunks [[MLMultiArray]]?

I have a large MLMultiArray of length 15360 values.
Sample:
Float32 1 x 15360
[14.78125,-0.6308594,5.609375,13.57812,-1.871094,-19.65625,9.5625,8.640625,-2.728516,3.654297,-3.189453,-1.740234...]
Is there a way I can convert this huge array into 120 small MLMultiArrays with 128 elements each without changing the sequence of this array and in the most efficient way possible?
The entire array of 15360 elements is available in this Link
let chunkSize = 2
let shape = yourLargeArray.shape
let chunkedArrays = try? stride(from: 0, to: shape.count, by: chunkSize)
.map { offset -> MLMultiArray in
let startIndex = shape.index(shape.startIndex, offsetBy: offset)
let endIndex = shape.index(startIndex, offsetBy: chunkSize, limitedBy: shape.endIndex) ?? shape.endIndex
return try MLMultiArray(
shape: Array(shape[startIndex ..< endIndex]),
dataType: yourLargeArray.dataType
)
}

Swift - Using stride with an Int Array

I want to add the numbers together and print every 4 elements, however i cannot wrap my head around using the stride function, if i am using the wrong approach please explain a better method
var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13]
func addNumbersByStride(){
var output = Stride...
//first output = 1+2+3+4 = 10
//second output = 5+6+7+8 = 26 and so on
print(output)
}
It seems you would like to use stride ...
let arr = [1,2,3,4,5,6,7,8,9,10,11,12,13]
let by = 4
let i = stride(from: arr.startIndex, to: arr.endIndex, by: by)
var j = i.makeIterator()
while let n = j.next() {
let e = min(n.advanced(by: by), arr.endIndex)
let sum = arr[n..<e].reduce(0, +)
print("summ of arr[\(n)..<\(e)]", sum)
}
prints
summ of arr[0..<4] 10
summ of arr[4..<8] 26
summ of arr[8..<12] 42
summ of arr[12..<13] 13
You can first split the array into chunks, and then add the chunks up:
extension Array {
// split array into chunks of n
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
// add each chunk up:
let results = numbers.chunked(into: 4).map { $0.reduce(0, +) }
If you would like to discard the last sum if the length of the original array is not divisible by 4, you can add an if statement like this:
let results: [Int]
if numbers.count % 4 != 0 {
results = Array(numbers.chunked(into: 4).map { $0.reduce(0, +) }.dropLast())
} else {
results = numbers.chunked(into: 4).map { $0.reduce(0, +) }
}
This is quite a basic solution and maybe not so elegant. First calculate and print sum of every group of 4 elements
var sum = 0
var count = 0
for n in stride(from: 4, to: numbers.count, by: 4) {
sum = 0
for i in n-4..<n {
sum += numbers[i]
}
count = n
print(sum)
}
Then calculate the sum of the remaining elements
sum = 0
for n in count..<numbers.count {
sum += numbers[n]
}
print(sum)

Generate random number of certain amount of digits

Hy,
I have a very Basic Question which is :
How can i create a random number with 20 digits no floats no negatives (basically an Int) in Swift ?
Thanks for all answers XD
Step 1
First of all we need an extension of Int to generate a random number in a range.
extension Int {
init(_ range: Range<Int> ) {
let delta = range.startIndex < 0 ? abs(range.startIndex) : 0
let min = UInt32(range.startIndex + delta)
let max = UInt32(range.endIndex + delta)
self.init(Int(min + arc4random_uniform(max - min)) - delta)
}
}
This can be used this way:
Int(0...9) // 4 or 1 or 1...
Int(10...99) // 90 or 33 or 11
Int(100...999) // 200 or 333 or 893
Step 2
Now we need a function that receive the number of digits requested, calculates the range of the random number and finally does invoke the new initializer of Int.
func random(digits:Int) -> Int {
let min = Int(pow(Double(10), Double(digits-1))) - 1
let max = Int(pow(Double(10), Double(digits))) - 1
return Int(min...max)
}
Test
random(1) // 8
random(2) // 12
random(3) // 829
random(4) // 2374
Swift 5: Simple Solution
func random(digits:Int) -> String {
var number = String()
for _ in 1...digits {
number += "\(Int.random(in: 1...9))"
}
return number
}
print(random(digits: 1)) //3
print(random(digits: 2)) //59
print(random(digits: 3)) //926
Note It will return value in String, if you need Int value then you can do like this
let number = Int(random(digits: 1)) ?? 0
Here is some pseudocode that should do what you want.
generateRandomNumber(20)
func generateRandomNumber(int numDigits){
var place = 1
var finalNumber = 0;
for(int i = 0; i < numDigits; i++){
place *= 10
var randomNumber = arc4random_uniform(10)
finalNumber += randomNumber * place
}
return finalNumber
}
Its pretty simple. You generate 20 random numbers, and multiply them by the respective tens, hundredths, thousands... place that they should be on. This way you will guarantee a number of the correct size, but will randomly generate the number that will be used in each place.
Update
As said in the comments you will most likely get an overflow exception with a number this long, so you'll have to be creative in how you'd like to store the number (String, ect...) but I merely wanted to show you a simple way to generate a number with a guaranteed digit length. Also, given the current code there is a small chance your leading number could be 0 so you should protect against that as well.
you can create a string number then convert the number to your required number.
func generateRandomDigits(_ digitNumber: Int) -> String {
var number = ""
for i in 0..<digitNumber {
var randomNumber = arc4random_uniform(10)
while randomNumber == 0 && i == 0 {
randomNumber = arc4random_uniform(10)
}
number += "\(randomNumber)"
}
return number
}
print(Int(generateRandomDigits(3)))
for 20 digit you can use Double instead of Int
Here is 18 decimal digits in a UInt64:
(Swift 3)
let sz: UInt32 = 1000000000
let ms: UInt64 = UInt64(arc4random_uniform(sz))
let ls: UInt64 = UInt64(arc4random_uniform(sz))
let digits: UInt64 = ms * UInt64(sz) + ls
print(String(format:"18 digits: %018llu", digits)) // Print with leading 0s.
16 decimal digits with leading digit 1..9 in a UInt64:
let sz: UInt64 = 100000000
let ld: UInt64 = UInt64(arc4random_uniform(9)+1)
let ms: UInt64 = UInt64(arc4random_uniform(UInt32(sz/10)))
let ls: UInt64 = UInt64(arc4random_uniform(UInt32(sz)))
let digits: UInt64 = ld * (sz*sz/10) + (ms * sz) + ls
print(String(format:"16 digits: %llu", digits))
Swift 3
appzyourlifz's answer updated to Swift 3
Step 1:
extension Int {
init(_ range: Range<Int> ) {
let delta = range.lowerBound < 0 ? abs(range.lowerBound) : 0
let min = UInt32(range.lowerBound + delta)
let max = UInt32(range.upperBound + delta)
self.init(Int(min + arc4random_uniform(max - min)) - delta)
}
}
Step 2:
func randomNumberWith(digits:Int) -> Int {
let min = Int(pow(Double(10), Double(digits-1))) - 1
let max = Int(pow(Double(10), Double(digits))) - 1
return Int(Range(uncheckedBounds: (min, max)))
}
Usage:
randomNumberWith(digits:4) // 2271
randomNumberWith(digits:8) // 65273410
Swift 4 version of Unome's validate response plus :
Guard it against overflow and 0 digit number
Adding support for Linux's device because "arc4random*" functions don't exit
With linux device don't forgot to do
#if os(Linux)
srandom(UInt32(time(nil)))
#endif
only once before calling random.
/// This function generate a random number of type Int with the given digits number
///
/// - Parameter digit: the number of digit
/// - Returns: the ramdom generate number or nil if wrong parameter
func randomNumber(with digit: Int) -> Int? {
guard 0 < digit, digit < 20 else { // 0 digit number don't exist and 20 digit Int are to big
return nil
}
/// The final ramdom generate Int
var finalNumber : Int = 0;
for i in 1...digit {
/// The new generated number which will be add to the final number
var randomOperator : Int = 0
repeat {
#if os(Linux)
randomOperator = Int(random() % 9) * Int(powf(10, Float(i - 1)))
#else
randomOperator = Int(arc4random_uniform(9)) * Int(powf(10, Float(i - 1)))
#endif
} while Double(randomOperator + finalNumber) > Double(Int.max) // Verification to be sure to don't overflow Int max size
finalNumber += randomOperator
}
return finalNumber
}

Swift Range Type endIndex

If you create a var Range = 0...0, I would expect the endIndex to be zero. But in reality is 1.
var myRange: Range<Int> = 0...0
print("start Index \(myRange.startIndex) End Index \(myRange.endIndex)")
output: "start Index 0 End Index 1"
How can I question a Range instance if an Index of type Int is contained ?
The endIndex is not actually included in the Range. The Range is startIndex ..< endIndex. So, for your example, 0...0 is stored as 0..<1 which means the same thing.
For Swift 1.2 you can use the global function contains to check if an Int is contained by a Range:
var myRange: Range<Int> = 0...0
let i: Int = 1
if contains(myRange, i) {
println("yes")
} else {
println("no") // prints "no"
}
For Swift 2.0:
var myRange: Range<Int> = 0...0
let i: Int = 1
if myRange.contains(i) {
print("yes")
} else {
print("no") // prints "no"
}
Maybe you could refer to Half-Open Range Operator
var myRange: Range<Int> = 0..<0
outputs:"start Index 0 End Index 0"
The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. And the closed range operator (a...b) will finally turn to (a..<b+1)
Because Range is also a collection, you can use its minElement() and maxElement() methods, which will return the correct index, respecting the range being closed (...) or half-open (..<).
So the below code will output zeros as expected:
let range: Range<Int> = 0...0
let min = range.minElement()!
let max = range.maxElement()!
print("min=\(min), max=\(max)")
// Output: "min=0, max=0"
Note: both methods have O(elements.count) complexity which might not be suitable for some cases.