Reputation: 75
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.
Upvotes: 4
Views: 356
Reputation: 17872
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} ]
Upvotes: 2
Reputation: 7678
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
.
Upvotes: 1