Looping through an array in SwiftUI - arrays

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)
}
}
}

Related

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")]

How to make my test pass a non mult-dimensional array to my React Test?

I have a utility method that I am writing a test for and I am trying to pass arguments to accurately portray usage and produce a non multi-dimensional array. Here is my code
const arrayInsert = (arr: any[], index: number, ...newItems) => [
...arr.slice(0, index),
...newItems,
...arr.slice(index)
];
export default arrayInsert;
As you see the last argument is a spread operator. And right now I am passing arguments to my test that produce a multi-dimensional array instead of adding to the array like this example:
arrayInsert(["A", "B", "F"], 1, "C", "D", "E");
// produces
["A", "C", "D", "E", "B", "F"]
So I want my test to be written to accurately portray the above example.
import arrayInsert from "./arrayInsert";
describe("arrayInsert", () => {
it("should return array containing an array of new items", () => {
const arr = ["A", "B", "F"];
const newItems = ["C", "D", "E"];
const index = 1;
const expected = ["A", ["C", "D", "E"], "B", "F"];
expect(arrayInsert(arr, index, newItems)).toEqual(expected);
});
});
How can I make the result one dimensional?

Creating sub-array from list of array indicies

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)

Swift - How to get indexes of filtered items of array

let items: [String] = ["A", "B", "A", "C", "A", "D"]
items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]
Does Swift 3 support a function like whatFunction(_: Element)?
If not, what is the most efficient logic?
You can filter the indices of the array directly, it avoids the extra mapping.
let items = ["A", "B", "A", "C", "A", "D"]
let filteredIndices = items.indices.filter {items[$0] == "A"}
or as Array extension:
extension Array where Element: Equatable {
func whatFunction(_ value : Element) -> [Int] {
return self.indices.filter {self[$0] == value}
}
}
items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]
or still more generic
extension Collection where Element: Equatable {
func whatFunction(_ value : Element) -> [Index] {
return self.indices.filter {self[$0] == value}
}
}
You can create your own extension for arrays.
extension Array where Element: Equatable {
func indexes(of element: Element) -> [Int] {
return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
}
}
You can simply call it like this
items.indexes(of: "A") // [0, 2, 4]
items.indexes(of: "B") // [1]
You can achieve this by chain of:
enumerated() - add indexes;
filter() out unnecessary items;
map() our indexes.
Example (works in Swift 3 - Swift 4.x):
let items: [String] = ["A", "B", "A", "C", "A", "D"]
print(items.enumerated().filter({ $0.element == "A" }).map({ $0.offset })) // -> [0, 2, 4]
Another way is using flatMap, which allows you to check the element and return index if needed in one closure.
Example (works in Swift 3 - Swift 4.0):
print(items.enumerated().flatMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]
But since Swift 4.1 flatMap that can return non-nil objects become deprecated and instead you should use compactMap.
Example (works since Swift 4.1):
print(items.enumerated().compactMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]
And the cleanest and the most memory-cheap way is to iterate through array indices and check if element of array at current index equals to required element.
Example (works in Swift 3 - Swift 5.x):
print(items.indices.filter({ items[$0] == "A" })) // -> [0, 2, 4]
In Swift 3 and Swift 4 you can do that:
let items: [String] = ["A", "B", "A", "C", "A", "D"]
extension Array where Element: Equatable {
func indexes(of item: Element) -> [Int] {
return enumerated().compactMap { $0.element == item ? $0.offset : nil }
}
}
items.indexes(of: "A")
I hope my answer was helpful 😊
you can use it like that :
let items: [String] = ["A", "B", "A", "C", "A", "D"]
let indexes = items.enumerated().filter {
$0.element == "A"
}.map{$0.offset}
print(indexes)
just copy and paste
extension Array {
func whatFunction(_ ids : String) -> [Int] {
var mutableArr = [Int]()
for i in 0..<self.count {
if ((self[i] as! String) == ids) {
mutableArr.append(i)
}
}
return mutableArr
}
}
You can use that below code:
var firstArray = ["k","d","r","r","p","k","b","p","k","k"]
var secondArray = ["k","d","r","s","d","r","b","c"]
let filterArray = firstArray.filter { secondArray.contains($0) }
let filterArray1 = firstArray.filter { !secondArray.contains($0) }
let filterIndex = firstArray.enumerated().filter { $0.element == "k" }.map { $0.offset }
print(filterArray) --> // ["k", "d", "r", "r", "k", "b", "k", "k"]
print(filterArray1) --> // ["p", "p"]
print(filterIndex) --> // [0, 5, 8, 9]
this can be a way too
// MARK: - ZIP: Dictionary like
let words = ["One", "Two", "Three", "Four"]
let numbers = 1...words.count
for (word, number) in zip(words, numbers) {
print("\n\(word): \(number)")
}
For example finding the indices of p_last values that are in inds1 array: (swift 4+)
let p_last = [51,42]
let inds1 = [1,3,51,42,4]
let idx1 = Array(inds1.filter{ p_last.contains($0) }.indices)
idx1 = [0,1]

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