Array map, Swift - ios

I have a custom Rules class.
class Rules: NSCoding {
var x: String?
var y: Double?
override func mapping(map: Map) {
self.x <- map["x"]
self.y <- map["y"]
}
In my viewModel I need to create an object rules and to pass 1 by 1 the elements of two array. The first array is composed by 3 strings, the second array has some Double (more than 3 !!)
This is what I tried so far:
let xValues = ["String1", "String2", "String3"]
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0]
let rules = zip(xValues, yValues).map {
Rules(x: "\($0.0)", y: $0.1)
}
The problem with this (I guess) is that my rules object has some duplicated string or sometimes more than what I have in my xValues array. (It's possible I am doing something wrong somewhere else ...)
What I need is to pass exactly three strings, and a number of Double which is different, lets say 6 double.

Since zip only returns tuples for those indices where both input arrays have have values, you'll need a method that fills up the smaller array instead, like this:
func zipFill<T, U>(_ arr1: [T], _ arr2: [U]) -> [(T?, U?)] {
let c1 = arr1.count
let c2 = arr2.count
let count = max(c1, c2)
var result = [(T?, U?)]()
for i in 0..<count {
if i < c1 && i < c2 {
result.append((arr1[i], arr2[i]))
} else if i >= c1 {
result.append((nil, arr2[i]))
} else if i >= c2 {
result.append((arr1[i], nil))
}
}
return result
}
let xValues = ["String1", "String2", "String3"]
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0]
let rules = zipFill(xValues, yValues).map {
Rules(x: $0.0, y: $0.1)
}
print(rules)
// [ {x "String1", y 1}, {x "String2", y 2}, {x "String3", y 1.5},
// {x nil, y 2.5}, {x nil, y 5.1}, {x nil, y 6}, {x nil, y 8} ]

Why don't you just remove duplicates before creating your rules?
Define a generic extension to remove duplicates:
extension RangeReplaceableCollection {
func removingDuplicates<E>(keyPath path: KeyPath<Element, E>) -> Self
where E: Hashable
{
var seen = Set<E>()
seen.reserveCapacity(count)
var new = self
new.removeAll { element -> Bool in
if seen.contains(element[keyPath: path]) {
return true
} else {
seen.insert(element[keyPath: path])
return false
}
}
return new
}
}
Then remove duplicates before zipping:
let xValues = ["String1", "String2", "String3"].removingDuplicates(keyPath: \.self)
let yValues = [1.0, 2.0, 1.5, 2.5, 5.1, 6.0, 8.0].removingDuplicates(keyPath: \.self)
let rules = zip(xValues, yValues).map {
Rules(x: $0.0, y: $0.1)
}
Tidbit: you don't need to use String interpolation for the x argument, because the parameter $0.0 is already a String.

Related

Custom NSCoding object, Swift (map)

I have this class :
class Point: NSCoding {
var x: String?
var y: Double?
override func mapping(map: Map) {
self.x <- map["x"]
self.y <- map["y"]
}
...
In my ViewModel I have a function that generates an array of Double.
I need to create a var with those Double to the y parameters of Points, and 2 string to the x parameters.
I've done something like this but this was with a Point object so everything fits.
let points = PointObject.map { point in
Point(x: point.x ?? "0", y: point.y ?? 0.0).self
}
Any suggestion/help? I'm not very familiar with this
Given two arrays of String/x and Double/y values:
let xValues = ["0", "1"]
let yValues = [2.0, 3.0]
you can create Points using zip and map
let points = zip(xValues, yValues).map {
Point(x: $0.0, y: $0.1)
}

Swift 5.1 Initialilize Array Multidimensional with unsafeUninitializedCapacity

In order to initialize a two-dimension Int array following
https://github.com/apple/swift-evolution/blob/master/proposals/0245-array-uninitialized-initializer.md
var myArray = Array<Int>(unsafeUninitializedCapacity: 10) { buffer, initializedCount in
for x in 1..<5 {
buffer[x] = x
}
buffer[0] = 10
initializedCount = 5
}
// myArray == [10, 1, 2, 3, 4]
I've tried next two code, but they doesn'work:
var myArray = [[Int]](unsafeUninitializedCapacity: 3) { bufferfilas, initializedCountfilas in
for x in 0..<3 {
bufferfilas[x] = [Int](unsafeUninitializedCapacity:3) {buffercolumnas, initializedCountcolumnas in
for y in 0..<3{
buffercolumnas[y] = y
}
initializedCountcolumnas = 3
}
}
initializedCountfilas = 9
}
And the second:
var myArray = [[Int]](var myArray = [[Int]](unsafeUninitializedCapacity: 9) { buffer, initializedCount in
for x in 0..<3 {
for y in 0..<3{
buffer[x][y] = (x*10)+y
}
}
initializedCount = 9
}
Which one is the correct way to initialize a two-dimension array in swift 5.1?
Thanks in advance.
Following is the initialiser declaration from docs
init(unsafeUninitializedCapacity: Int, initializingWith initializer: (inout UnsafeMutableBufferPointer<Element>, inout Int) throws -> Void) rethrows
To create a 2D dimensional array the Element should be another array.
Following is the example if you want your second array to be initialise as normal array instead of using the unsafeUninitializedCapacity
var my2DArray = Array<Array<Int>>(unsafeUninitializedCapacity: 10) { (buffer: inout UnsafeMutableBufferPointer<Array<Int>>, count: inout Int) in
for a in 0..<5 {
buffer[a] = [a]
}
count = 5
}
For the unsafe version
var my2DArrayUnsafe = Array<Array<Int>>(unsafeUninitializedCapacity: 10) { (buffer: inout UnsafeMutableBufferPointer<Array<Int>>, count: inout Int) in
for a in 0..<5 {
buffer[a] = Array<Int>(unsafeUninitializedCapacity: 10, initializingWith: { (subBuffer: inout UnsafeMutableBufferPointer<Int>, subCount: inout Int) in
for subA in 0..<5 {
subBuffer[subA] = subA
}
subCount = 5
})
}
count = 5
}

how to compare pairwise elements of a CGPoint array to determine which has a greater x position

I have an array of CGPoints (which are arranged in a specific order) [A1, A2,...,AN]. How can I compare the elements in pairs of two to determine which has a greater x position? For example, comparing A1.x with A2.x, A2.x with A3.x, A3.x with A4.x and so on all the way to AN.x with A1.x (comparing elements in specific order).
I wrote extension function pairwiseCompare(index: Self.Index?) -> Bool?, that take index of element and compare this element with next (or with first, if it is last):
extension CollectionType where Generator.Element == CGPoint {
func pairwiseCompare(index: Self.Index?) -> Bool? {
guard let index = index where startIndex.distanceTo(index) >= 0 && index.distanceTo(endIndex) > 0 else {
return nil
}
let secondIndex = index.successor() == endIndex ? startIndex : index.successor()
return self[index].x > self[secondIndex].x
}
func pairwiseCompare() -> [Bool] {
var result = [Bool]()
for index in startIndex..<endIndex {
result.append(pairwiseCompare(index)!)
}
return result
}
}
Usage:
let array = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 5, y: 1)]
print(array.pairwiseCompare(-1)) // nil
print(array.pairwiseCompare(0)) // Optional(false)
print(array.pairwiseCompare(1)) // Optional(false)
print(array.pairwiseCompare(2)) // Optional(true)
print(array.pairwiseCompare(3)) // nil
print(array.pairwiseCompare()) // [false, false, true]

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

Create an array of random numbers in Swift

I'm just starting to learn Swift.
I'm attempting to create an array of several random numbers, and eventually sort the array. I'm able to create an array of one random number, but what's the best way to iterate this to create an array of several random numbers?
func makeList() {
var randomNums = arc4random_uniform(20) + 1
let numList = Array(arrayLiteral: randomNums)
}
makeList()
In Swift 4.2 there is a new static method for fixed width integers that makes the syntax more user friendly:
func makeList(_ n: Int) -> [Int] {
return (0..<n).map { _ in .random(in: 1...20) }
}
Edit/update: Swift 5.1 or later
We can also extend Range and ClosedRange and create a method to return n random elements:
extension RangeExpression where Bound: FixedWidthInteger {
func randomElements(_ n: Int) -> [Bound] {
precondition(n > 0)
switch self {
case let range as Range<Bound>: return (0..<n).map { _ in .random(in: range) }
case let range as ClosedRange<Bound>: return (0..<n).map { _ in .random(in: range) }
default: return []
}
}
}
extension Range where Bound: FixedWidthInteger {
var randomElement: Bound { .random(in: self) }
}
extension ClosedRange where Bound: FixedWidthInteger {
var randomElement: Bound { .random(in: self) }
}
Usage:
let randomElements = (1...20).randomElements(5) // [17, 16, 2, 15, 12]
randomElements.sorted() // [2, 12, 15, 16, 17]
let randomElement = (1...20).randomElement // 4 (note that the computed property returns a non-optional instead of the default method which returns an optional)
let randomElements = (0..<2).randomElements(5) // [1, 0, 1, 1, 1]
let randomElement = (0..<2).randomElement // 0
Note: for Swift 3, 4 and 4.1 and earlier click here.
Ok, this is copy/paste of a question asked elsewhere, but I think I'll try to remember that one-liner:
var randomArray = map(1...100){_ in arc4random()}
(I love it!)
If you need a random number with an upperBound (exclusive), use arc4random_uniform(upperBound).
E.g.: random number between 0 and 99: arc4random_uniform(100)
Swift 2 update
var randomArray = (1...100).map{_ in arc4random()}
Swift 5
This creates an array of size 5, and whose elements range from 1 to 10 inclusive.
let arr = (1...5).map( {_ in Int.random(in: 1...10)} )
Swift 4.2 or later
func makeList(_ n: Int) -> [Int] {
return (0..<n).map{ _ in Int.random(in: 1 ... 20) }
}
let list = makeList(5) //[11, 17, 20, 8, 3]
list.sorted() // [3, 8, 11, 17, 20]
How about this? Works in Swift 5 and Swift 4.2:
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
return Array(0..<size).shuffled()
}
}
Usage:
let array = Array.generateRandom(size: 10)
print(array)
Prints e.g.:
[7, 6, 8, 4, 0, 3, 9, 2, 1, 5]
The above approach gives you unique numbers. However, if you need redundant values, use the following implementation:
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
var result = Array(repeating: 0, count: size)
for index in 0..<result.count {
result[index] = Int.random(in: 0..<size)
}
return result
}
}
A shorter version of the above using map():
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
var result = Array(repeating: 0, count: size)
return result.map{_ in Int.random(in: 0..<size)}
}
}

Resources