Forgive the contrived example below, but how can I filter like this? Using a Set
to dedup isn't an option since my real data objects have another property that is unique for each.
struct MyDataObject {
var startDate: Date
var endDate: Date
}
let dataObject1 = MyDataObject(startDate: Date().startOfDay(), endDate: Date().startOfDay())
let duplicateDataObject = MyDataObject(startDate: Date().startOfDay(), endDate: Date().startOfDay())
let array = [dataObject1, duplicateDataObject]
//How to filter to end up with an array of data objects with a unique start date?
CodePudding user response:
https://github.com/apple/swift-algorithms/blob/main/Guides/Unique.md
import Algorithms
array.uniqued(on: \.startDate)
Or, if you need more control of which elements get chosen:
array.uniqued(on: \.startDate) { [$0, $1].max(by: \.endDate)! }
import struct OrderedCollections.OrderedDictionary
public extension Sequence {
@inlinable func uniqued<Subject: Hashable>(
on projection: (Element) throws -> Subject,
uniquingWith combine: (Element, Element) throws -> Element
) rethrows -> [Element] {
try OrderedDictionary(keyed(by: projection), uniquingKeysWith: combine)
.values
.elements
}
@inlinable func max<Comparable: Swift.Comparable>(
by getComparable: (Element) throws -> Comparable
) rethrows -> Element? {
try self.max {
try getComparable($0) < getComparable($1)
}
}
}
public extension Sequence {
@inlinable func keyed<Key: Hashable>(
by key: (Element) throws -> Key
) rethrows -> [KeyValuePairs<Key, Element>.Element] {
try map { (try key($0), $0) }
}
}
CodePudding user response:
Do you mean filter so you only keep elements that appear exactly once in the original collection?
import OrderedCollections
struct A {
let id: String
let thing: String
}
let things: [A] = [
.init(id: "1", thing: "thing"),
.init(id: "2", thing: "thing"),
.init(id: "3", thing: "thing"),
.init(id: "2", thing: "thing"),
.init(id: "1", thing: "thing"),
.init(id: "4", thing: "thing"),
.init(id: "2", thing: "thing"),
]
let uniqueThings = OrderedDictionary<String, [A]>(grouping: things, by: \.id)
.filter { $0.value.count == 1 }
.values
Gives just the A's with unique id's (of 3 and 4 in this example)
Or do you mean just to deduplicate, like https://github.com/apple/swift-algorithms/blob/main/Guides/Unique.md uniqued(on:)
and if so which element should be retained if there are more than one, the first seen, the last etc?