Created
July 16, 2024 23:20
-
-
Save chockenberry/d6c08e9916442d11a0c69fb01454c063 to your computer and use it in GitHub Desktop.
Ugly Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
enum Name { | |
case foo(Foo) | |
case bar(Bar) | |
struct Foo { | |
let name: String | |
} | |
struct Bar { | |
let count: Int | |
} | |
} | |
let names = [Name.foo(Name.Foo(name: "hello")), Name.bar(Name.Bar(count: 123)), Name.bar(Name.Bar(count: 999))] | |
// The goal: to get the first Name.Bar item from names, and more importantly, to make the code readable. | |
func firstBar_TakeOne(in names: [Name]) -> Name.Bar? { | |
if case let .bar(bar) = names.first(where: { name in | |
if case .bar(_) = name { | |
return true | |
} | |
return false | |
}) { | |
return bar | |
} | |
return nil | |
} | |
func firstBar_TakeTwo(in names: [Name]) -> Name.Bar? { | |
let initialResult: Name.Bar? = nil | |
let result = names.reduce(into: initialResult) { result, name in | |
guard result == nil else { return } | |
if case let .bar(bar) = name { | |
result = bar | |
} | |
} | |
return result | |
} | |
if let bar = firstBar_TakeOne(in: names) { | |
bar.count | |
} | |
if let bar = firstBar_TakeTwo(in: names) { | |
bar.count | |
} |
If you use the asBar
or barValue
helper values others have contributed above, you could then write it as:
return names.lazy.compactMap(\.asBar).first
and still get nearly optimal performance. A regular for loop will probably be marginally faster for small collections though but not by much.
Watch out, the performance of that construct may surprise you: https://forums.swift.org/t/adding-firstas-to-sequence/36665/17
Ahhhh, overloads fun. 🙃 The first(where: { _ in true })
hack is terrible, too 😂 but if abstracted over and provided with a very good explanatory comment, I guess I could live with it. 🙃
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would tend to reach for something like this:
The combination of
.lazy
and.first
should mean you only iterate as far through the collection as you need to, and the result is anOptional<Name.Bar>
.