Int array to Int standard method - ios

I am trying to convert an Int array to an Int number. What I am now
doing is converting it to a String array and then use the joined() function. Is there a more efficient way to do this?
Example:
let sortedIntArray = String(number).characters.map{Int(String($0)) ?? 0}.sorted(by: { $0 > $1 })
let desOrder = Int(sortedIntArray.map{String($0)}.joined())!

In your case, sortedIntArray is an array of single-digit numbers,
and then you can combine them without any conversion to strings:
let sortedIntArray = [4, 2, 1]
let result = sortedIntArray.reduce(0) { 10 * $0 + $1 }
print(result) // 421
Combined with the dfri's elegant solution to split the number
into an integer array:
let number = 1439
let descDigits = sequence(state: number, next: { (num: inout Int) -> Int? in
return num > 0 ? (num % 10, num /= 10).0 : nil
}).sorted(by: >)
print(descDigits) // [9, 4, 3, 1]
let descNumber = descDigits.reduce(0) { 10 * $0 + $1 }
print(descNumber) // 9431

Use the reduce method instead of map and joined
let desOrder = Int(sortedIntArray.reduce("") { $0 + String($1) })
reduce(intialResult: Result, (Result, Any) throws -> Result) rethrows

You asked about efficiency, as to this answer by Martin R, my guess is that is the most efficient answer
var number = 1992843
var arr = [Int]()
while number > 0 {
arr.append(number % 10)
number = number / 10
}
arr.sort()
arr.reverse()
for n in arr {
number = number * 10
number += n
}

Related

How to remove character from odd index in Swift String

I am new to swift & I have to remove characters from odd index from a given String
I did try with following code
var myStringObject = "HelloTestString"
myStringObject.enumerated().filter({ index, char in !(char == "1" && index % 2 == 0) })
but I am unable to find the desired result string. Can you please guide me how to remove characters from odd index in String.
You can't filter by two filter types. So you have to move to the old approach.
var myStringObject = "HelloTestString"
var newString = ""
var index = 0
while index < myStringObject.count {
if index % 2 != 0 {
let firstIndex: String.Index = myStringObject.startIndex
let desiredChar: Character = myStringObject[myStringObject.index(firstIndex, offsetBy: index)]
newString = newString + "\(desiredChar)"
}
index = index + 1
}
print(newString) //elTsSrn
Keeping your starting solution:
let couples = myStringObject.enumerated().filter { (arg0) -> Bool in
let (offset, _) = arg0
return offset % 2 == 0
}
print(couples)
or
let couples = myStringObject.enumerated().filter { (offset, _) -> Bool in
return offset % 2 == 0
} //Which is more similar to last version
You have then, an array of Tuples where first element is the offset, and the second the element.
$>[(offset: 0, element: "H"), (offset: 2, element: "l"), (offset: 4, element: "o"), (offset: 6, element: "e"), (offset: 8, element: "t"), (offset: 10, element: "t"), (offset: 12, element: "i"), (offset: 14, element: "g")]
Let's keep only the letters (and back to String, not a String.Element):
let onlyletters = couples.map({ String($0.element) })
Let's get it back into a String.
let result = onlyletters.joined()
In one line:
let oneLine = myStringObject.enumerated().filter({ $0.0 % 2 == 0 }).map({ String($0.element) }).joined()
You can create an auxiliary index and use defer to increase it after each iteration on your collection, this way you don't need to enumerate your string:
let string = "HelloTestString"
var index = 0
let filtered = string.filter { _ in
defer { index += 1 }
return index % 2 == 1
}
print(filtered) // "elTsSrn"
If you need to mutate your original string you can use removeAll with the same approach:
var string = "HelloTestString"
var index = 0
string.removeAll { _ in
defer { index += 1 }
return index % 2 == 0
}
print(string)
Implementing your own method
extending RangeReplaceableCollection to filter or removeAll elements that are in odd or even positions:
extension RangeReplaceableCollection {
var oddIndicesElements: Self {
var position = 0
return filter { _ in
defer { position += 1 }
return position % 2 == 1
}
}
var evenIndicesElements: Self {
var position = 0
return filter { _ in
defer { position += 1 }
return position % 2 == 0
}
}
mutating func removeAllEvenIndicesElements() {
var position = 0
removeAll { _ in
defer { position += 1 }
return position % 2 == 0
}
}
mutating func removeAllOddIndicesElements() {
var position = 0
removeAll { _ in
defer { position += 1 }
return position % 2 == 1
}
}
}
var myStringObject = "HelloTestString"
print(myStringObject.oddIndicesElements) // "elTsSrn"
myStringObject.removeAllEvenIndicesElements()
print(myStringObject) // "elTsSrn"

Jaro Winkler distance in Objective-C or Swift

I need to do fuzzy comparison of a large number of strings and am looking at Jaro-Winkler which respects differences in the order of letters. Is anyone aware of a way to do this in Objective-C or Swift either using Jaro-Winkler or some method native to IOS?
Thanks for any recommendations or suggestions.
I took an inspiration in Apache Commons and rewritten it to Swift:
extension String {
static func jaroWinglerDistance(_ first: String, _ second: String) -> Double {
let longer = Array(first.count > second.count ? first : second)
let shorter = Array(first.count > second.count ? second : first)
let (numMatches, numTranspositions) = jaroWinklerData(longer: longer, shorter: shorter)
if numMatches == 0 {
return 0
}
let defaultScalingFactor = 0.1;
let percentageRoundValue = 100.0;
let jaro = [
numMatches / Double(first.count),
numMatches / Double(second.count),
(numMatches - numTranspositions) / numMatches
].reduce(0, +) / 3
let jaroWinkler: Double
if jaro < 0.7 {
jaroWinkler = jaro
} else {
let commonPrefixLength = Double(commonPrefix(first, second).count)
jaroWinkler = jaro + Swift.min(defaultScalingFactor, 1 / Double(longer.count)) * commonPrefixLength * (1 - jaro)
}
return round(jaroWinkler * percentageRoundValue) / percentageRoundValue
}
private static func commonPrefix(_ first: String, _ second: String) -> String{
return String(
zip(first, second)
.prefix { $0.0 == $0.1 }
.map { $0.0 }
)
}
private static func jaroWinklerData(
longer: Array<Character>,
shorter: Array<Character>
) -> (numMatches: Double, numTranspositions: Double) {
let window = Swift.max(longer.count / 2 - 1, 0)
var shorterMatchedChars: [Character] = []
var longerMatches = Array<Bool>(repeating: false, count: longer.count)
for (offset, shorterChar) in shorter.enumerated() {
let windowRange = Swift.max(offset - window, 0) ..< Swift.min(offset + window + 1, longer.count)
if let matchOffset = windowRange.first(where: { !longerMatches[$0] && shorterChar == longer[$0] }) {
shorterMatchedChars.append(shorterChar)
longerMatches[matchOffset] = true
}
}
let longerMatchedChars = longerMatches
.enumerated()
.filter { $0.element }
.map { longer[$0.offset] }
let numTranspositions: Int = zip(shorterMatchedChars, longerMatchedChars)
.lazy
.filter { $0.0 != $0.1 }
.count / 2
return (
numMatches: Double(shorterMatchedChars.count),
numTranspositions: Double(numTranspositions)
)
}
}
Tested by the examples found in the original code:
print(String.jaroWinglerDistance("", ""))
print(String.jaroWinglerDistance("", "a"))
print(String.jaroWinglerDistance("aaapppp", ""))
print(String.jaroWinglerDistance("frog", "fog"))
print(String.jaroWinglerDistance("fly", "ant"))
print(String.jaroWinglerDistance("elephant", "hippo"))
print(String.jaroWinglerDistance("hippo", "elephant"))
print(String.jaroWinglerDistance("hippo", "zzzzzzzz"))
print(String.jaroWinglerDistance("hello", "hallo"))
print(String.jaroWinglerDistance("ABC Corporation", "ABC Corp"))
print(String.jaroWinglerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc."))
print(String.jaroWinglerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"))
print(String.jaroWinglerDistance("PENNSYLVANIA", "PENNCISYLVNIA"))
I have also found another implementation of String similarity functions in github.

Tracking specific data in string using Swift

I'm still new to coding in general, and I'm running into an issue with a Swift exercise.
How do I track the number of times 1 (var numberOfSteps) and the number of times 2 (var numberOfHeartBeats) appears in the string "12221231221"?
I'm given the following hint but not sure how the for-in loop applies:
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
print(character)
}
In the loop, you can check what the current characters is, then increment the variable accordingly:
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
if character == "1" {
numberOfSteps += 1
} else if character == "2" {
numberOfHeartBeats += 1
}
}
Here is another more functional way of doing this:
let dict = Dictionary(grouping: activityData, by: { $0 }).mapValues { $0.count }
dict["1"] is numberOfSteps and dict["2"] is numberOfHeartBeats.
If you want to use a for loop you can do
let activityData = "12221231221"
var numberOfSteps = 0
var numberOfHeartBeats = 0
for character in activityData{
switch character {
case "1":
numberOfSteps += 1
case "2":
numberOfHeartBeats += 1
default:
break
}
}
print("Number of steps: \(numberOfSteps), number of hartbeats: \(numberOfHeartBeats)")
A more condensed solution without a loop
print("Number of steps: \( activityData.filter( {$0 == "1"} ).count), number of hartbeats: \( activityData.filter( {$0 == "2"} ).count)")
You can do this in simple way like this:-
let occurrencesOne = text.characters.filter { $0 == "1" }.count
let occurrencesTwo = text.characters.filter { $0 == "2" }.count
Another solution is to use reduce, this is kinda equivalent to manually looping over the string, but will less and mode concise code, and without the disadvantage of creating intermediary structures (like arrays of dictionaries), which for large inputs can be problematic memory-wise:
let activityData = "12221231221"
let numberOfSteps = activityData.reduce(0) { $1 == "1" ? $0 + 1 : $0 }
let numberOfHeartBeats = activityData.reduce(0) { $1 == "2" ? $0 + 1 : $0 }
print(numberOfSteps, numberOfHeartBeats) // 4, 6
One step further to reduce the duplication would be to add a function to compute the reduce second parameter:
func countIf<T: Equatable>(_ search: T) -> (Int, T) -> Int {
return { $1 == search ? $0 + 1 : $0 }
}
let activityData = "12221231221"
let numberOfSteps: Int = activityData.reduce(0, countIf("1"))
let numberOfHeartBeats = activityData.reduce(0, countIf("2"))
print(numberOfSteps, numberOfHeartBeats)

Limit the results of a Swift array filter to X for performance

I have about 2000 elements in my array, and when it is filtered, I would like to end the filtering as soon as I have 5 elements in my filtered array.
Currently it is:
providerArray.filter({($0.lowercased().range(of:((row.value as? String)?.lowercased())!) != nil)})
which can return up to 2000 results which is a waste of processing, and time.
To be more clear, I need a solution that is equivalent to limiting the filter results like I can with coreData fetches [request setFetchLimit:5];
The fastest solution in terms of execution time seems to be an
explicit loop which adds matching elements until the limit is reached:
extension Sequence {
public func filter(where isIncluded: (Iterator.Element) -> Bool, limit: Int) -> [Iterator.Element] {
var result : [Iterator.Element] = []
result.reserveCapacity(limit)
var count = 0
var it = makeIterator()
// While limit not reached and there are more elements ...
while count < limit, let element = it.next() {
if isIncluded(element) {
result.append(element)
count += 1
}
}
return result
}
}
Example usage:
let numbers = Array(0 ..< 2000)
let result = numbers.filter(where: { $0 % 3 == 0 }, limit: 5)
print(result) // [0, 3, 6, 9, 12]
You can use .lazy too boost the performance a bit:
let numbers: [Int] = Array(0 ..< 2000)
let result: AnySequence = numbers
.lazy
.filter {
print("Calling filter for: \($0)")
return ($0 % 3) == 0
}
.prefix(5)
print(Array(result))
This will call the filter function only for the first 15 values (until it finds 5 that pass the filter).
Now you can concentrate on boosting the performance of the filter itself. E.g. by caching values. You don't have to do this but if some values keep repeating, it can boost the performance a lot.
let numbers: [Int] = Array(0 ..< 2000)
var filterCache: [Int: Bool] = [:]
let result: AnySequence = numbers
.lazy
.filter {
if let cachedResult = filterCache[$0] {
return cachedResult
}
print("Calling filter for: \($0)")
let result = (($0 % 3) == 0)
filterCache[$0] = result
return result
}
.prefix(5)
print(Array(result))
You can apply this method directly to your function.
Also note that to boost performance, you should either:
save ((row.value as? String)?.lowercased())! into a local variable because it is executed multiple times
simplify the expression using options:
let result: AnySequence = providerArray
.lazy
.filter {
$0.range(of: row.value as! String, options: [.caseInsensitive]) != nil
}
.prefix(5)

Calculate all permutations of a string in Swift

For the string "ABC" the code snippet below calculates 5 of the 6 total permutations. My strategy was to insert each character at each index possible index. But the function never gets "CBA" as a possible permutation. What am I missing?
var permutationArray:[String] = [];
let string: String = "ABC"
func permute(input: String) -> Array<String>
{
var permutations: Array<String> = []
/* Convert the input string into characters */
var inputArray: Array<String>
inputArray = input.characters.map { String($0) }
print(inputArray)
/* For each character in the input string... */
for var i = 0; i < inputArray.count; i++
{
/* Insert it at every index */
let characterInArray: String = inputArray[i]
var inputArrayCopy: Array<String> = []
for var y = 0; y < inputArray.count; y++
{
inputArrayCopy = inputArray
inputArrayCopy.removeAtIndex(i)
inputArrayCopy.insert(characterInArray, atIndex:y)
let joiner = ""
let permutation = inputArrayCopy.joinWithSeparator(joiner)
if !permutations.contains(permutation) {
permutations.insert(permutation, atIndex: 0)
}
}
}
return permutations
}
var permutations = permute(string)
print(permutations)
While Stefan and Matt make a good point about using Heap's algorithm, I think you have an important question about why your code doesn't work and how you would debug that.
In this case, the algorithm is simply incorrect, and the best way to discover that is with pencil and paper IMO. What you are doing is picking each element, removing it from the array, and then injecting it into each possible location. Your code does what you have asked it to do. But it's not possible to get to "CBA" that way. You're only moving one element at a time, but "CBA" has two elements out of order. If you expanded to ABCD, you'd find many more missing permutations (it only generates 10 of the 24).
While Heap's algorithm is nicely efficient, the deeper point is that it walks through the entire array and swaps every possible pair, rather than just moving a single element through the array. Any algorithm you choose must have that property.
And just to throw my hat into the ring, I'd expand on Matt's implementation this way:
// Takes any collection of T and returns an array of permutations
func permute<C: Collection>(items: C) -> [[C.Iterator.Element]] {
var scratch = Array(items) // This is a scratch space for Heap's algorithm
var result: [[C.Iterator.Element]] = [] // This will accumulate our result
// Heap's algorithm
func heap(_ n: Int) {
if n == 1 {
result.append(scratch)
return
}
for i in 0..<n-1 {
heap(n-1)
let j = (n%2 == 1) ? 0 : i
scratch.swapAt(j, n-1)
}
heap(n-1)
}
// Let's get started
heap(scratch.count)
// And return the result we built up
return result
}
// We could make an overload for permute() that handles strings if we wanted
// But it's often good to be very explicit with strings, and make it clear
// that we're permuting Characters rather than something else.
let string = "ABCD"
let perms = permute(string.characters) // Get the character permutations
let permStrings = perms.map() { String($0) } // Turn them back into strings
print(permStrings) // output if you like
Here's an expression of Heap's (Sedgewick's?) algorithm in Swift. It is efficient because the array is passed by reference instead of being passed by value (though of course this means you must be prepared to have the array tampered with). Swapping is efficiently expressed through the use of the built-in swapAt(_:_:) function:
func permutations(_ n:Int, _ a: inout Array<Character>) {
if n == 1 {print(a); return}
for i in 0..<n-1 {
permutations(n-1,&a)
a.swapAt(n-1, (n%2 == 1) ? 0 : i)
}
permutations(n-1,&a)
}
Let's try it:
var arr = Array("ABC".characters)
permutations(arr.count,&arr)
Output:
["A", "B", "C"]
["B", "A", "C"]
["C", "A", "B"]
["A", "C", "B"]
["B", "C", "A"]
["C", "B", "A"]
If what you wanted to do with each permutation was not merely to print it, replace print(a) with something else. For example, you could append each permutation to an array, combine the array of characters into a string, whatever.
A very straightforward approach as also suggested in Swift coding challenges.
func permutation(string: String, current: String = "") {
let length = string.characters.count
let strArray = Array(string.characters)
if (length == 0) {
// there's nothing left to re-arrange; print the result
print(current)
print("******")
} else {
print(current)
// loop through every character
for i in 0 ..< length {
// get the letters before me
let left = String(strArray[0 ..< i])
// get the letters after me
let right = String(strArray[i+1 ..< length])
// put those two together and carry on
permutation(string: left + right, current: current +
String(strArray[i]))
}
}
}
Apple today released an Algorithms package available at:
https://github.com/apple/swift-algorithms
This package includes a permutations function that works like so:
let string = "abc"
string.permutations()
/*
["a", "b", "c"]
["a", "c", "b"]
["b", "a", "c"]
["b", "c", "a"]
["c", "a", "b"]
["c", "b", "a"]
*/
func generate(n: Int, var a: [String]){
if n == 1 {
print(a.joinWithSeparator(""))
} else {
for var i = 0; i < n - 1; i++ {
generate(n - 1, a: a)
if n % 2 == 0 {
let temp = a[i]
a[i] = a[n-1]
a[n-1] = temp
}
else {
let temp = a[0]
a[0] = a[n-1]
a[n-1] = temp
}
}
generate(n - 1, a: a)
}
}
func testExample() {
var str = "123456"
var strArray = str.characters.map { String($0) }
generate(str.characters.count, a: strArray)
}
Don't reinvent the wheel. Here's a simple port of Heap's algorithm.
Here is my solution.
import Foundation
class Permutator {
class func permutation(_ str: String) -> Set<String> {
var set = Set<String>()
permutation(str, prefix: "", set: &set)
return set
}
private class func permutation(_ str: String, prefix: String, set: inout Set<String>) {
if str.characters.count == 0 {
set.insert(prefix)
}
for i in str.characters.indices {
let left = str.substring(to: i)
let right = str.substring(from: str.index(after: i))
let rem = left + right
permutation(rem, prefix: prefix + String(str[i]), set: &set)
}
}
}
let startTime = Date()
let permutation = Permutator.permutation("abcdefgh")
print("\(permutation) \n")
print("COMBINAISON: \(permutation.count)")
print("TIME: \(String(format: "%.3f", Date().timeIntervalSince(startTime)))s")
You can copy/paste it in a file and execute it with the command line swift binary.
For a permutation of 7 all unique characters, this algorithm take around 0,06 second to execute.
I was searching to solve the same problem, but I wanted a solution that worked with Generic data type, so I wrote one by looking at a scala code (http://vkostyukov.ru/posts/combinatorial-algorithms-in-scala/)
https://gist.github.com/psksvp/8fb5c6fbfd6a2207e95638db95f55ae1
/**
translate from Scala by psksvp#gmail.com
http://vkostyukov.ru/posts/combinatorial-algorithms-in-scala/
*/
extension Array
{
func combinations(_ n: Int) -> [[Element]]
{
guard self.count > 0 else {return [[Element]]()}
guard n <= self.count else {return [[Element]]()}
if 1 == n
{
return self.map {[$0]}
}
else
{
let head = self.first! // at this point head should be valid
let tail = Array(self.dropFirst())
let car = tail.combinations(n - 1).map {[head] + $0} // build first comb
let cdr = tail.combinations(n) // do the rest
return car + cdr
}
}
func variations(_ n:Int) -> [[Element]]
{
func mixone(_ i: Int, _ x: Element, _ ll: [Element]) -> [Element]
{
return Array( ll[0 ..< i] + ([x] + ll[i ..< ll.count]) )
}
func foldone(_ x: Element, _ ll: [Element]) -> [[Element]]
{
let r:[[Element]] = (1 ... ll.count).reduce([[x] + ll])
{
a, i in
[mixone(i, x, ll)] + a
}
return r
}
func mixmany(_ x: Element, _ ll: [[Element]]) -> [[Element]]
{
guard ll.count > 0 else {return [[Element]]()}
let head = ll.first!
let tail = Array<Array<Element>>(ll.dropFirst())
return foldone(x, head) + mixmany(x, tail)
}
guard self.count > 0 else {return [[Element]]()}
guard n <= self.count else {return [[Element]]()}
if 1 == n
{
return self.map {[$0]}
}
else
{
let head = self.first! // at this point head should be valid
let tail = Array(self.dropFirst())
return mixmany(head, tail.variations(n - 1)) + tail.variations(n)
}
}
var permutations: [[Element]]
{
variations(self.count)
}
}
print([1, 2, 3, 4].combinations(2))
print([1, 2, 3, 4].variations(2))
print([1, 2, 3, 4].permutations)
print(Array("ABCD").permutations)
100% working tested
func permute(strInput:String,l:Int,r:Int){
var inputCharacter = Array(strInput)
if ( l==r){
print(strInput)
}else{
for var i in l..<r{
// Swapping done
inputCharacter.swapAt(l, i);
// Recursion called
permute(strInput: String(inputCharacter), l: l+1, r: r);
//backtrack
inputCharacter.swapAt(l, i);
}
}
}
This way you can call method:
permute(strInput: "ABC", l: 0, r: 3)
Output:
ABC
ACB
BAC
BCA
CBA
CAB
You can use the functions of this framework to calculate permutations and combinations both with repetition and without repetition. You can investigate the source code and compare with your own.
https://github.com/amirrezaeghtedari/AECounting
This library calculates the results based on lexicographic order. For example the result of permutation 3 items out of 5 items are same as below:
let result = Permutation.permute(n: 5, r: 3)
//result
//[
// [1, 2, 3],
// [1, 2, 4],
// [1, 2, 5],
// ...,
// 5, 4, 3]
//].
You can easily assign your problem items to 1 to n numbers in the result array.
In case of your problem, you should call:
let result = Permutation.permute(n: 3, r: 3)
For those looking to calculate all permutations of an array:
func permutations<T>(_ arr: [T]) -> [[T]] {
if arr.count < 2 {
return [arr]
}
var ret: [[T]] = []
let rest = Array(arr[1...])
for p in permutations(rest) {
for i in 0...p.count {
ret.append(Array(p[0..<i]) + [arr[0]] + Array(p[i...]))
}
}
return ret
}
🚨 Update: just use array.permuations() as noted by #Caleb

Resources