skip to Main Content

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?

2

Answers


  1. 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) }
      }
    }
    
    Login or Signup to reply.
  2. 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?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search