Split a String in an [[Int]] - swift

I have a String and want to split it into an [[Int]]
let string = "1,2,3;4,5,6;7,8,9" // comma and semicolon separators!
The result should be
[[1,2,3],[4,5,6],[7,8,9]]
I know hot to split into an [Int] by using
let string = "1,2,3,4,5,6,7,8,9"
var intArray = string.split(separator: ",").compactMap { Int($0) }
but I have no idea how to split it into [[Int]]
I tried
var intArray = string.split(separator: ";").split(separator: ",").compactMap { Int($0) }
This first split creates a [String], but the second split doesn't work
Solution
A friend helped me with it, so I want to provide the solution here, too:
var intArray = string.split(separator: ";").map { $0.split(separator: ",").compactMap { Int($0) } }

This is the one-liner you were looking for
import UIKit
let string = "1,2,3;4,5,6;7,8,9"
var intArray = string.split(separator: ";").map {$0.split(separator: ",").map {Int($0)!} }
print(intArray)
Alternatively, you could use the components method to split by semicolon, applying a forEach on the resulting array, in order to append the same array split by comma, on which a map has been applied to convert it from [String] to [Int].
var array : [[Int]] = []
string.components(separatedBy: ";").forEach { sub in
array.append((sub.components(separatedBy: ",")).map { Int($0)!} )
}
print(array)
Both will output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Related

Get all values into dictionary and create a String with a specific format

I have a dictionary with this structure:
a: [1,2]
b: [3,4]
c: [5,6]
and I need to return a string with this structure.
a,b,c\n1,3,5\n2,4,6
I solved the first part of the string. But to get the rest of the String. I try to iterate into my dictionary to get the first elements for each key in my dictionary and then get the rest for each value into the array.
Is there an easier way to get this?
Once you know what's the order of the keys (alpha ?), you can use this:
let dict: [String: [Int]] = ["a": [1,2], "b": [3, 4], "c": [5, 6]]
let keys = dict.keys.sorted() //Or do whatever you want here to get your target order
var matrix: [[String]] = []
keys.forEach {
guard let arrayAsInt = dict[$0] else { return }
let arrayAsString = arrayAsInt.map{ "\($0)" }
matrix.append( [$0] + arrayAsString)
}
print("Matrix: \(matrix)")
let transposed = matrix.transposed()
print("Transposed Matrix: \(transposed)")
let output = transposed.map { $0.joined(separator: ",")}.joined(separator: "\n")
print(output)
The outputs:
$>Matrix: [["a", "1", "2"], ["b", "3", "4"], ["c", "5", "6"]]
$>Transposed Matrix: [["a", "b", "c"], ["1", "3", "5"], ["2", "4", "6"]]
$>a,b,c
1,3,5
2,4,6
Obvisouly the "\n" might be invisible and be an actual new line
a,b,c
1,3,5
2,4,6
Being
a,b,c\n1,3,5\n2,4,6
What's the idea behind that? Create a matrix and use the transpose (it's used in maths with matrix, it's one of the basic modification of a matrix).
First transform the [String: [Int]] into a [[String]], where each element would be key followed by its values. I transformed it there as String for simpler code later.
Why doing that? Because the matrix value is easy to get from your initial dict. the transposed value is harder (not impossible) to get from dict but easier from matrix, and the transposed is quickly transformed into your format.
So my thinking was the reverse:
Get a structure from your output, then how to get it, it's a transpose, so I need to get the initial input as it, etc.
With the help of a code for Transpose Matrix (that accept String elements).
extension Collection where Self.Iterator.Element: RandomAccessCollection {
// PRECONDITION: `self` must be rectangular, i.e. every row has equal size.
func transposed() -> [[Self.Iterator.Element.Iterator.Element]] {
guard let firstRow = self.first else { return [] }
return firstRow.indices.map { index in
self.map{ $0[index] }
}
}
}
Any code (there a various) working ones, should the trick. I took it from here.
As pointed by #Leo Dabus, you can remove the Self.Iterator.Element
from the extension code (twice). I just wanted to it as such, not modifying the initial answer since it's not mind.
What you are looking for, besides composing the final string, is how to transpose a collection (this would work with collections of different sizes as well):
extension Sequence {
func max<T: Comparable>(_ predicate: (Element) -> T) -> Element? {
self.max(by: { predicate($0) < predicate($1) })
}
}
extension Collection where Element: RandomAccessCollection, Element.Indices == Range<Int> {
func transposed() -> [[Element.Element]] {
(0..<(max(\.count)?.count ?? .zero)).map {
index in compactMap { $0.indices ~= index ? $0[index] : nil }
}
}
}
let dict = ["a": [1,2,3],
"b": [4,5,6],
"c": [7,8,9]]
let sorted = dict.sorted(by: {$0.key < $1.key})
let result = sorted.map(\.key).joined(separator: ",") + "\n" +
sorted.map(\.value).transposed().map {
$0.map(String.init).joined(separator: ",")
}.joined(separator: "\n")
result // "a,b,c\n1,4,7\n2,5,8\n3,6,9"
A dictionary is an unordered collection so you need to sort it according to any specific key. Here I sort the dictionary according to the key if you don't care about an order you can just remove sort.
let dict: [String: Any] = ["a": [1,2], "b": [3,4], "c": [5,6]]
let sortedKey = dict.keys.sorted(by: <)
let key = sortedKey.joined(separator: ",")
var firstValues: [String] = []
var secondValues: [String] = []
sortedKey.forEach { (key) in
if let dictValue = dict[key] as? [Int],
let firstValue = dictValue.first,
let secondValue = dictValue.last {
firstValues.append("\(firstValue)")
secondValues.append("\(secondValue)")
}
}
let finalString = key + "\n" + firstValues.joined(separator: ",") + "\n" + secondValues.joined(separator: ",")
print(finalString) // "a,b,c\n1,3,5\n2,4,6"

Swift Sets creating a visual of them and searching through them

I have looked on google and wasn't able to find a library that would allow me to create an image of all the sets. I was wondering if anyone new if such a library existed.
My second question is that at the moment I am doing
// create sets
var set1: Set = [2, 3, 5, 7]
var set2: Set = [2, 3, 4, 6]
var set3: Set = [1, 3, 8, 7]
var new: Set = [2,3]
var finally = [String]()
if(new.isSubset(of:set1)
{
finally.append("set1")
}
if(new.isSubset(of:set2)
{
finally.append("set2")
}
if(new.isSubset(of:set3)
{
finally.append("set3")
}
print(finally)
this is a horrible way of doing it and have been working on a function that automates this process. I tried to create a list of sets:
var foo = [set1,set2,set3]
the issue with that is that I lose the name of the sets since the output is
[{5,7,2,3},{6,2,4,3},{7,3,1,8}]
therefore I decided to create a dictionary:
var baz = [ 'a': set1,
'b': set2,
'c': set3]
//for loop through dictionary
var finally2 = [String]()
for(key,value) in baz {
if(newset.isSubset(of: value))
{
finally2.append(key)
}
}
print(finally2)
I don't like my final dictionary solution and was wondering if there was a better solution just using sets.
I suggest using array and exploiting the fact that array elements has an order, if you insist of using sets you can use the same solution with NSOrderedSet because sets does not have an order.
var set1: Set = [2, 3, 5, 7]
var set2: Set = [2, 3, 4, 6]
var set3: Set = [1, 3, 8, 7]
var new: Set = [2,3]
//let or:NSOrderedSet = [set1, set2, set3] // NSOrderedSet
let ArrayOfSets: Array = [set1, set2, set3]
let finalArry: [String] = ArrayOfSets.flatMap {
if new.isSubset(of: $0) {
let i = ArrayOfSets.index(of: $0)
return "Set\(String(describing: i!+1))"
}
return ""
}.filter{ $0 != ""}
print(finalArry) //["Set1", "Set2"]
You can do the same with for loop of course

How to compare to arrays whether the objects of one array are there in the other or not

let say we have:
var a = ["z", "x"]
var b = ["z", "x", "c", "d"]
now i want to check whether objects of array a are there in array b or not..
thanks for your time..
The simplest way is to use map in combination with contains:
let matches = map(a) { return contains(b, $0) }
contains checks to see if an item is in a collection
map is used to convert one array into another array with an element-by-element mapping.
As pointed out by #marcos, there are similar variants to answer the any and all questions as well
let any = a.reduce(false) { acc, item in return acc || contains(b, item) }
let all = a.reduce(true) { acc, item in return acc && contains(b, item) }
Just use the map:
var a = [1, 7, 5, 2]
var b = [1, 2, 3, 4]
let d = a.map { b.contains($0) }
print(d) // [true, false, false, true]
I think this following code snippet wil work:
var booleanArray = [Bool]()
for x in a{
if !contains(b, x){
booleanArray.append(false)
}
else{
booleanArray.append(true)
}
You can use a for in loop and then use the array contains function:
Swift 2.0
var resultsArray : [Bool] = [Bool]()
let a = ["a","b","c"]
let b = ["a","c"]
for letter in a {
if b.contains(letter) == true {
// Letter exists in a array
resultsArray.append(true)
} else {
// Letter does not exist in a array
resultsArray.append(false)
}
}
Swift 1.2
Replace b.contains(letter) with:
contains(b, letter)
You could convert the arrays to Set to use the intersect method
let a = ["a","c"]
let b = ["a","b","c","d"]
let aSet = Set(a)
let bSet = Set(b)
let intersection = aSet.intersect(bSet) // ["a", "c"]

Randomize two arrays the same way Swift

I know there is a new shuffle method with iOS 9
but I am wondering if there is anyway to shuffle two arrays the same way?
For example
[1,2,3,4] and [a,b,c,d]
shuffle
[3,4,1,2] and [c,d,a,b]
Using the shuffle() method from How do I shuffle an array in Swift? and the ideas from How can I sort multiple arrays based on the sorted order of another array
you can shuffle the array indices and then re-order both (or more)
arrays accordingly:
let a = [1, 2, 3, 4]
let b = ["a", "b", "c", "d"]
var shuffled_indices = a.indices.shuffle()
let shuffled_a = Array(PermutationGenerator(elements: a, indices: shuffled_indices))
let shuffled_b = Array(PermutationGenerator(elements: b, indices: shuffled_indices))
print(shuffled_a) // [3, 1, 2, 4]
print(shuffled_b) // ["c", "a", "b", "d"]
Update for Swift 3 (Xcode 8): PermutationGenerator does not
exist in Swift 3 anymore.
Using the shuffled() method
from Shuffle array swift 3 the same can be achieved with
var shuffled_indices = a.indices.shuffled()
let shuffled_a = shuffled_indices.map { a[$0] }
let shuffled_b = shuffled_indices.map { b[$0] }
Use a dictionary to store the values temporarily, shuffle the keys and then rebuild the other array by extracting the values from the dictionary.
I'm unaware of any built-in shuffle mechanism in Swift 2.0. Assuming this doesn't exist, I borrowed some code from here.
extension CollectionType where Index == Int {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
let shuffleOrder = [0,1,2,3]
let shuffled = shuffleOrder.shuffle()
var newArray1 = [String]()
var newArray2 = [String]()
let array1 = ["a", "b", "c", "d"]
let array2 = ["w", "x", "y", "z"]
shuffled.forEach() { index in
newArray1.append(array1[index])
newArray2.append(array2[index])
}
This solves the problem in a really straight forward way. It creates an array, shuffleOrder, that just has an index for each possible index in the starting arrays. It then shuffles these indices to create a random sampling order. Finally, it constructs two new arrays, based off of the starting arrays, sampling them with the shuffled values. While this doesn't mutate the original 2 arrays in place, it would be simple to modify this to do so.
Based upon Martin R's original answer, you could approach the problem using GameKit.
The answer is written in Swift4:
var arrayA = [1, 2, 3, 4]
var arrayB = ["a", "b", "c", "d"]
//Get The Indices Of The 1st Array
var shuffledIndices: [Int] = Array(arrayA.indices)
print("Shuffled Indices = \(shuffledIndices)")
//Shuffle These Using GameKit
shuffledIndices = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: shuffledIndices) as! [Int]
//Map The Objects To The Shuffled Indices
arrayA = shuffledIndices.map { arrayA[$0] }
arrayB = shuffledIndices.map { arrayB[$0] }
//Log The Results
print("""
Array A = \(arrayA)
Array B = \(arrayB)
""")
Hope it helps ^_________^.

How to remove an element of a given value from an array in Swift

I want to remove all elements of value x from an array that contains x, y and z elements
let arr = ['a', 'b', 'c', 'b']
How can I remove all elements of value 'b' from arr?
A filter:
let farray = arr.filter {$0 != "b"}
If you need to modify initial array, you can use the function removeAll(where:) that is available in Swift 4.2/Xcode 10:
var arr = ["a", "b", "c", "b"]
arr.removeAll(where: { $0 == "b" })
print(arr) // output is ["a", "c"]
However, if you are using Xcode 9 you can find this function in Xcode9to10Preparation (this library provides implementations of some new functions from Xcode 10).
var array : [String]
array = ["one","two","one"]
let itemToRemove = "one"
while array.contains(itemToRemove) {
if let itemToRemoveIndex = array.index(of: itemToRemove) {
array.remove(at: itemToRemoveIndex)
}
}
print(array)
Works on Swift 3.0.
EDITED according to comments:
I like this approach:
var arr = ["a", "b", "c", "b"]
while let idx = arr.index(of:"b") {
arr.remove(at: idx)
}
Original answer (before editing):
let arr = ['a', 'b', 'c', 'b']
if let idx = arr.index(of:"b") {
arr.remove(at: idx)
}
In Swift 3 I simply do:
arr = arr.filter { $0 != "a" }
.filter, .sort and .map are great for saving time and solve lots of problems with little code.
This article has good examples and explain the differences and how they work: https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/
If you have more than one element to remove, thanks to first answer.
var mainArray = ["a", "b", "qw", "qe"]
let thingsToRemoveArray = ["qw", "b"]
for k in thingsToRemoveArray {
mainArray = mainArray.filter {$0 != k}
}
A general approach is to exploit first class procedures. (However, this approach is much more powerful than what is required for your question.) To illustrate, say you want to avoid "Justin" repeatedly in many collections.
let avoidJustin = notEqualTester ("Justin")
let arrayOfUsers = // ...
arrayOfUsers.filter (avoidJustin)
let arrayOfFriends = // ...
arrayOfFriends.filter (avoidJustin)
With this, you avoid repeatedly creating a closure each time you want to avoid Justin. Here is notEqualTester which, given a that, returns a function of this that returns this != that.
func notEqualTester<T: Equatable> (that:T) -> ((this:T) -> Bool) {
return { (this:T) -> Bool in return this != that }
}
The returned closure for this captures the value for that - which can be useful when that is no longer available.
If you only have one element of that value, this would probably be the easiest.
arr.remove(at: arr.index(of: ‘b’))