Creating sub-array from list of array indicies - arrays

I have an enum with a computed property that returns an array of indicies:
enum ScaleDegree {
case tonic
case supertonic
case mediant
case subdominant
case dominant
case submedian
case leading
var indexes: [Int] {
switch self {
case .tonic: return [0,2,4]
case .supertonic: return [1,3,5]
case .mediant: return [2,4,6]
case .subdominant: return [3,5,0]
case .dominant: return [4,6,1]
case .submedian: return [5,0,2]
case .leading: return [6,1,3]
}
}
}
I use this to extract a subarry from a larger array:
let cMajor = ["C", "D", "E", "F", "G", "A", "B"]
let cMajorTonic = [cMajor[ScaleDegree.tonic.indexes[0]], cMajor[ScaleDegree.tonic.indexes[1]], cMajor[ScaleDegree.tonic.indexes[2]]]
The cMajorTonic syntax seems cumbersome and I would expect Swift 4 would give me an easier way to extract individual elements into a new array, but my searching hasn't found a clever way to do this.
Are there any suggestions of a better way to write this?

This would be a good place to use map:
let cMajor = ["C", "D", "E", "F", "G", "A", "B"]
let cMajorTonic = ScaleDegree.tonic.indexes.map { cMajor[$0] }
print(cMajorTonic)
["C", "E", "G"]
You could add this function to your enum:
func appliedTo(scale: [String]) -> [String] {
return self.indexes.map { scale[$0] }
}
And then it would become:
let cMajorTonic = ScaleDegree.tonic.appliedTo(scale: cMajor)

Related

Divide array into subarrays

I have the following array, I have to make sure to divide it in this way into subarray, taking into consideration the first part of the name followed by / as a criterion for subdivision, for example "name/other".
Can you give me a hand?
var a = ["origin/a", "origin/b", "origin/c", "remo/a", "remo/d", "remo/c", "next/g"]
var b = {
origin: ["a", "b", "c"],
remo: ["a", "d", "c"],
next: ["g"]
}
You could used reduce(into:_:) to do so:
let reduced = a.reduce(into: [String: [String]]()) { partialResult, currentTerm in
let components = currentTerm.components(separatedBy: "/")
guard components.count == 2 else { return }
partialResult[components[0]] = partialResult[components[0], default: [String]()] + [components[1]]
}
print(reduced)
Output:
$>["remo": ["a", "d", "c"], "next": ["g"], "origin": ["a", "b", "c"]]
One idea is like this:
First we need to separate the keys for the dictionary and all the values that need to be gathered together:
let keysValues = a
.map { $0.components(separatedBy: "/") }
.compactMap { components -> (String, String)? in
guard components.count == 2 else { return nil }
return (components.first!, components.last!)
}
Now we need to reduce that into a dictionary of [String: [String]] by grouping together the values for each key:
var dict: [String: [String]] = [:]
let answer = keysValues.reduce(into: dict) { (d, kv) in
let (k, v) = kv
d[k, default: []] += [v]
}

Compare each element in two arrays Swift

I have two arrays of strings. for example:
let arrayFirst: [String] = ["A", "A", "A", "A", "A"]
let arraySecond: [String] = ["A", "C", "A", "B", "A"]
I need to compare this two arrays each element in array and return for every sequence bool state.
For example here will be answer:
let resultArray: [Bool] = [true, false, true, false, true]
how to do it better?
You can consider using the zip function.
let resultArray = zip(arrayFirst, arraySecond).map {
return $0.0 == $0.1
}
This will work even you have arrays of different length as zip will ignore the additional elements of the longer array.

Looping through an array in SwiftUI

I have an array of strings I want to loop through and create a view for each element. To achieve that, I tried using ForEach(), the output of the code below are the following errors:
Cannot convert value of type '[String]' to expected argument type 'Binding<C>'
Generic parameter 'C' could not be inferred
Code:
struct HomeView: View {
let array: [String] = ["A", "B", "C", "D", "E", "F", "G"]
var body: some View {
VStack {
ForEach(array, id: \.self) { letter in
Text(array[letter])
}
}
}
}
PS: The code is simplified
Desired output:
VStack of all letters from the array
You can try this (just use the letter parameter from the for loop):
let array: [String] = ["A", "B", "C", "D", "E", "F", "G"]
var body: some View {
VStack {
ForEach(array, id: \.self) { letter in
Text(letter)
}
}
}

Get items with the same position from multidimensional array in Swift 5

I can't find the best way to do this.
I have an array with 3 arrays in there(this never change)
var ancho = [String]()
var largo = [String]()
var cantidad = [String]()
var arrayDeCortes = [ancho,largo,cantidad]
arrayDeCortes = [[a,b,c,d,..],[e,f,g,h,..],[i,j,k,l,..]]
I need to get this:
[a,e,i]
[b,f,j]
[c,g,k]
[d,h,l]
My problem is that I don't know how many items there is in each array(ancho,largo,cantidad)
and how access to all of them.
I hope you understand me
You can use reduce(into:_:) function of Array like this:
let arrayDeCortes = [["a","b","c","d"],["e","f","g","h"],["i","j","k","l"]]
let arrays = arrayDeCortes.reduce(into: [[String]]()) { (result, array) in
array.enumerated().forEach {
if $0.offset < result.count {
result[$0.offset].append($0.element)
} else {
result.append([$0.element])
}
}
}
print(arrays)
// [["a", "e", "i"], ["b", "f", "j"], ["c", "g", "k"], ["d", "h", "l"]]
Edit: As #Alexander mentioned in the comments, there is a simpler way of achieving this by using zip(_:_:) function twice.
The following will return an array of tuples:
var widths = ["a","b","c","d"]
var heights = ["e","f","g","h"]
var quantities = ["i","j","k","l"]
let result = zip(widths, zip(heights, quantities)).map { width, pair in
(width, pair.0, pair.1)
}
print(result)
// [("a", "e", "i"), ("b", "f", "j"), ("c", "g", "k"), ("d", "h", "l")]

Xcode Swift check if array contains object

I have this array :
var preferiti : [ModalHomeLine!] = []
I want to check if the array contains the same object.
if the object exists {
} else {
var addPrf = ModalHomeLine(titolo: nomeLinea, link: linkNumeroLinea, immagine : immagine, numero : titoloLinea)
preferiti.append(addPrf)
}
Swift has a generic contains function:
contains([1,2,3,4],0) -> false
contains([1,2,3,4],3) -> true
So it sounds like you want an array without duplicate objects. In cases like this, a set is what you want. Surprisingly, Swift doesn't have a set, so you can either create your own or use NSSet, which would look something like this:
let myset = NSMutableSet()
myset.addObject("a") // ["a"]
myset.addObject("b") // ["a", "b"]
myset.addObject("c") // ["a", "b", "c"]
myset.addObject("a") // ["a", "b", "c"] NOTE: this doesn't do anything because "a" is already in the set.
UPDATE:
Swift 1.2 added a set type! Now you can do something like
let mySet = Set<String>()
mySet.insert("a") // ["a"]
mySet.insert("b") // ["a", "b"]
mySet.insert("c") // ["a", "b", "c"]
mySet.insert("a") // ["a", "b", "c"] NOTE: this doesn't do anything because "a" is already in the set.

Resources