I just learned about the wonderful world of map, flatMap and reduce in swift and I already use it where ever it makes sense and helps improve my code.
Now I encountered a very special problem and I wonder if there is a solution to this using map, flatMap and/or reduce.
In my model class, I have a optional array of other models. These models have a optional Bool property. I now want to know if the whole array of models contains at least one with a true property. This is what I'm currently doing:
class ModelA{
var bModels: [ModelB]?
}
class ModelB{
var aBool: Bool?
}
func hasATrue(aModel: ModelA) {
guard let bModels = aModel.bModels else { return false }
for bModel in bModels {
if bModel.aBool == true {
return true
}
}
return false
}
You can do this all in a single expression with optional chaining, Array.contains(where:) and nil coalescence.
func hasATrue(aModel: ModelA) {
return aModel.bModels?.contains(where: { $0.aBool == true }) ?? false
}
As per the comments on my question, this is what will do the trick:
return aModel.bModels?.contains(where: { $0.aBool == true }) ?? false
or alternatively
return aModel.bModels?.contains(where: { $0.aBool == true }) == true
Is one better than the other? I don't know. Maybe a Swift expert with deep knowledge about how the language is implemented can tell which one is faster/more efficient but for me, that method is called rarely and processing time is therefore not an issue but that is another topic.
Thanks to all the commenters. I was so fascinated by map, flatMap and reduce that I did not see the obvious (nor did I know that you can pass a closure to a contains function in swift). From day to day I like the language more and more.
I'm almost crying every time I have to write the Java code for Android π
Related
return value == String(value.reversed())
This is what I tried. It works well but takes a little bit longer. Does anyone know a better way?
There is nothing available in the standard library for String, or for anything else, so a solution for only String probably isn't the best option.
You don't need to make a new instance of anything based on reversed; elementsEqual does the job.
public extension Sequence where Element: Equatable {
var isSymmetric: Bool { elementsEqual(reversed()) }
}
"πππ
ππ".isSymmetric // true
"πππ
".isSymmetric // false
You could in c test each character one at a time from beginning and end until your two indices meet in the middle. But for Swift you don't have a guarantee that characters are the same length in a Swift String, they have to store strings that are made of unicode characters which can have one of 100,000's of characters at the moment, I think they currently do this by storying the String using UTF16. So you can not just use offset logic to quickly calculate the index for a character, you have to enumerate through each character, checking the length of each character to get to the next. Objective-C made this even more complicated with the potential of private subclasses of NSString, each could have different encoding methods.
A less expensive way than reversing the array is to walk simultaneously from the beginning and the end to the middle and compare each character - or whatever the Element of the type conforming to BidirectionalCollection is.
public extension BidirectionalCollection where Element: Equatable {
var isPalindrome: Bool {
if isEmpty { return true }
var π = startIndex
var π = index(before: endIndex)
while π < π {
if self[π] != self[π] { return false }
formIndex(after: &π)
formIndex(before: &π)
}
return true
}
}
I am looking for the way to write short syntax.
For instance. In JS, PHP and etc.
var a = 1 ;
function Foo ()-> void {}
a && Foo() ;
if a exists, run Foo.
a and Foo itself already mean exist or not, the syntax is away better looks....
However, in Swift, the typing checking is kinda of tough.
var a = 1 ;
func Foo ()-> Foid {} ;
a && Foo();
will generate neither are Bool returning error.
a != nil && Foo() ;
this can resolve and variable condition, but what if the better bypass for the function condition? I just dont want to write something like
if( a != nil ) { Foo() } ;
Yet what is the better syntax for Not Exist?
if ( !a ) or !a //is easy and better looks...
I found not similar thing in swift...
if( a == nil ) // will throws error when its not Optional Typing.
guard var b = xxx else {} // simply for Exist and very long syntax.
Thank you for your advice!
As mentioned by other contributors, Swift emphasizes readability and thus, explicit syntax. It would be sacrilege for the Swift standard library to support Python-style truth value testing.
That being said, Swiftβs extensibility allows us to implement such functionality ourselvesβif we really want to.
prefix func !<T>(value: T) -> Bool {
switch T.self {
case is Bool.Type:
return value as! Bool
default:
guard Double(String(describing: value)) != 0
else { return false }
return true
}
}
prefix func !<T>(value: T?) -> Bool {
guard let unwrappedValue = value
else { return false }
return !unwrappedValue
}
var a = 1
func foo() -> Void { }
!a && !foo()
Or even define our own custom operator:
prefix operator β
prefix func β<T>(value: T) -> Bool {
/// Same body as the previous example.
}
prefix func β<T>(value: T?) -> Bool {
guard let unwrappedValue = value
else { return false }
return βunwrappedValue
}
var a = 1
func foo() -> Void { }
βa && βfoo()
The expectations you've developed from dynamic languages like PHP and JS (and Ruby, Python for that matter) are almost universally inapplicable to static languages like Swift.
Swift is a statically compiled language. If you reference a variable that doesn't exist, it's not legal Swift code, and the compiler will fail your build. Given that, the question of "how do I check if a variable is undefined?" is completely moot in Swift. If you have a successfully compiling program that references a variable a, then a exists. There's absolutely no reason for a check, and so a mechanism for it doesn't even exist.
Static vs Dynamic typing
Static type systems are like mathematical proof systems. They produce rigerous proofs that certain aspects of your program are valid. This has trade-offs. The rigidity buys you many guarantees. For example, you'll never have a valid Swift program where you accidentally pass an Int where a Bool is expected. The static type system makes that class of error literally impossible, so it's not something you have to remember to check for yourself.
On the other hand, many truths are easier to intuit than to prove. Thus, there's great utility in scripting and dynamic languages, because they don't demand the rigorous proofs of your claims that static languages require. On the down side, their type systems "do" much less. For example, JS happily lets you reference an undefined variable. To remedy this, JS provides a way for you to do a run-time check to see whether a variable is defined or not. But this isn't a problem Swift has, so the "solution" is absent.
When static typing is too hard
Swift actually takes a middle ground position. If you find yourself with a statement that's obviously true, but hard to prove to the compiler, various "escape hatches" exist that allow you to leave the safety of the type system, and go into dynamic land. For example, if you look at an IBOutlet, and see that it's connected to an element in a storyboard, you can intuitively be sure that the IBOutlet is not nil. But that's not something you can prove to the compiler, and hence when you see implicitly unwrapped optionals being used for IBOutlets.
Implicitly unwrapped optionals are one such "escape hatch". The Any type is another, as is unsafeBitcast(_:to:), withoutActuallyEscaping(_:), as!, try!, etc.
Swift takes type safety very seriously. Unlike C or JS we can not use anything that doesn't resolve to Bool value type in If statement in Swift. So there won't be a short hand for that(at-least that I know of). Regarding below code
if( a == nil ) // will throws error when its not Optional Typing.
Swift doesn't allow you to set nil to non optional types. So there is no need to check for nil. By the way both Obj-C and Swift use verbose syntax, we need to get use to that.
In this case you are trying to force Swift to work in a way that you are used to with other languages like JavaScript or PHP, as you say in your comment. There are a few reasons why your code won't compile, but it mainly falls on the fact that Swift doesn't do the same truthy and falsy stuff JS does.
var a = 1
if a {
print("won't compile")
}
//'Int' is not convertible to 'Bool'
In Swift it's better to use an actual Bool value if that's what it's supposed to be, or if it's truly supposed to be an Int you're just going to have to check the value
var a = true
if a {
print("this compiles")
}
or
var a = 1
if a > 0 {
print("this compiles too")
}
Swift really isn't meant to be as loose as JS, so you should just embrace that and take advantage of the safety and readability.
Here is one way most similar to what you designed.
You may have to set the type of a to Int?:
var a: Int? = 1
func foo ()-> Void {}
a.map{_ in foo()}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm learning Swift and I'm facing a problem in one of my model classes.
What I'm trying to do is having a lazy-loaded property that can be "invalidated" when the data it is based on changes. (something like this: https://stackoverflow.com/a/25954243/2382892)
What I have now is something like this:
class DataSet {
var entries: [Entry]
var average: Double? {
return self.entries.average
}
}
Array<Entry>.average computes the average of a property of Entry, but returns nil if the array is empty.
Since this average could potentially be expensive to compute, I'd like to do that lazily and store a cached value of it and recalculate it only if necessary (when DataSet.entries is modified).
Now, following this answer, I should do something like this:
class DataSet {
var entries: [Entry]
var _average: Double?
var average: Double? {
if _average == nil {
_average = self.entries.average
}
return _average
}
}
However I have the problem of handling both the case that the average is to be recomputed, and when the array is empty and there's no meaningful average to return.
Since I know the average value will always be positive, I could use a default value (such as -1.0) to indicate the cache is no more valid, and nil to mean there are no entries, or vice-versa (nil means the average has to be computed again; -1.0 when there are no entries).
This however doesn't seem elegant, or the "Swift way" to achieve this behavior (or is it indeed?).
What should I do?
You definitely shouldn't use magic values, like -1 to indicate some state. But I agree that you should not use nil to indicate both that "the cached value is invalidated and must be recalculated" as well as "the cached average has been calculated and is nil because there were zero Entry objects". The problem with the other solutions that suggest just setting the calculated value to nil is that it can't distinguish between the two states of "invalidated" and "calculated but nil" and may call entries.average even though you may have already done so. Admittedly, this is likely not computationally expensive, but it is conflating two very different states.
One Swift solution would be an enum:
class DataSet {
private enum CachedValue {
case Calculated(Double?)
case Invalidated
}
var entries = [Entry]() {
didSet {
cachedAverage = .Invalidated
}
}
private var cachedAverage: CachedValue = .Invalidated
var average: Double? {
switch cachedAverage {
case .Calculated(let result):
return result
case .Invalidated:
let result = entries.average
cachedAverage = .Calculated(result)
return result
}
}
}
This captures a distinct state between .Invalidated and .Calculated and recalculates lazily as needed.
You can make use of didSet:
class DataSet {
var entries: [Entry] {
didSet {
/// just mark the average as outdated, it will be
/// recomputed when someone asks again for it
averageOutOfDate = true
}
}
/// tells us if we should recompute, by default true
var averageOutOfDate = true
/// cached value that avoid the expensive computation
var cachedAverage: Double? = nil
var average: Double? {
if averageOutOfDate {
cachedAverage = self.entries.average
averageOutOfDate = false
}
return cachedAverage
}
}
Basically whenever the entries property value changes, you mark the cached value as outdated, and you use this flag to know when to recompute it.
appzYourLife's answer is a nice concrete solution. However, I suggest a differ approach all-together. Here's what I would do:
I would make a protocol that defines all the important bits that would need to be access externally.
I would then make 2 structs/classes conform to this protocol.
The first struct/class will be a caching layer.
The second struct/class will be the actual implementation, which will only ever be accessed by the caching layer.
The caching layer will have a private instance of the actual implementing struct/class, and will have a variable such as "isCacheValid", which will be set to false by all mutating operations that invalidate the underlying data (and by extension, computed values such as the average).
This design makes it so that the actual implementing struct/class is fairly simple, and completely agnostic to the caching.
The caching layer does all the caching duties, completely agnostic to details of how the cached values are computed (as their computation is just delegated to the implementing class.
Use nil
First of all never use a specific value of your type domain to indicate the absence of value. In other words don't use a negative number to indicate no value. nil is the answer here.
So average should be declared as Double?.
Clearing the cache when entries does change
Next you need to clear your cache each time entries is mutated. You can use didSet for this.
class DataSet {
private var entries: [Entry] = [] {
didSet { cachedAverage = nil }
}
private var cachedAverage: Double?
var average: Double? {
if cachedAverage == nil {
cachedAverage = self.entries.average
}
return cachedAverage
}
}
When entries is empty
Finally if you believe that average for an empty array should be nil, then why don't you change accordingly the average computed property you added to SequenceType?
I'm writing some debug code to which I need to pass a parameter of type Any. For printing purposes I'd like to unwrap the parameter value iff it's an optional, but I can't figure out how to test that - every syntactic form I can think of is rejected by the compiler. E.g.,
switch val {
case as Optional<Any>:
.
.
and a variety of let forms (including trying .dynamicType) aren't legitimate. Does anyone know how to actually do this? Overall, what I'm trying to accomplish is such that whether or not the value is an optional, I get the actual value into a string and not Optional.
Martin is absolutely correct. From the linked post, modified slightly because I wanted a different return for nil:
func unwrap(any:Any, ifNil: Any = "nil") -> Any {
let mi = Mirror(reflecting: any)
if mi.displayStyle != .Optional {
return any
}
if mi.children.count == 0 { return ifNil }
let (_, some) = mi.children.first!
return some
}
I would like to learn and use more functional programming in Swift. So, I've been trying various things in playground. I don't understand Reduce, though. The basic textbook examples work, but I can't get my head around this problem.
I have an array of strings called "toDoItems". I would like to get the longest string in this array. What is the best practice for handling the initial nil value in such cases? I think this probably happens often. I thought of writing a custom function and use it.
func optionalMax(maxSofar: Int?, newElement: Int) -> Int {
if let definiteMaxSofar = maxSofar {
return max(definiteMaxSofar, newElement)
}
return newElement
}
// Just testing - nums is an array of Ints. Works.
var maxValueOfInts = nums.reduce(0) { optionalMax($0, $1) }
// ERROR: cannot invoke 'reduce' with an argument list of type β(nil, (_,_)->_)'
var longestOfStrings = toDoItems.reduce(nil) { optionalMax(count($0), count($1)) }
It might just be that Swift does not automatically infer the type of your initial value. Try making it clear by explicitly declaring it:
var longestOfStrings = toDoItems.reduce(nil as Int?) { optionalMax($0, count($1)) }
By the way notice that I do not count on $0 (your accumulator) since it is not a String but an optional Int Int?
Generally to avoid confusion reading the code later, I explicitly label the accumulator as a and the element coming in from the serie as x:
var longestOfStrings = toDoItems.reduce(nil as Int?) { a, x in optionalMax(a, count(x)) }
This way should be clearer than $0 and $1 in code when the accumulator or the single element are used.
Hope this helps
Initialise it with an empty string "" rather than nil. Or you could even initialise it with the first element of the array, but an empty string seems better.
Second go at this after writing some wrong code, this will return the longest string if you are happy with an empty string being returned for an empty array:
toDoItems.reduce("") { count($0) > count($1) ? $0 : $1 }
Or if you want nil, use
toDoItems.reduce(nil as String?) { count($0!) > count($1) ? $0 : $1 }
The problem is that the compiler cannot infer the types you are using for your seed and accumulator closure if you seed with nil, and you also need to get the optional type correct when using the optional string as $0.