A Swift collection of unique, ordered objects

Related tags

Utility OrderedSet
Overview

Introduction

OrderedSet is essentially the Swift equivalent of Foundation's NSOrderedSet/NSMutableOrderedSet. It was created so Swift would have a unique, ordered collection with fast lookup performance that supported strong typing through Generics, and so we could store Swift structs and enums in it.

Usage

OrderedSet works very much like an Array. Here are some basic examples of its usage:

var set = OrderedSet<Int>()
set.append(1)
set.contains(1) // => true
set[0] = 2
set[0] // => 2
set.insert(3, at: 0)
set // => [3, 2]
set = [1,2,3] // OrderedSet's support array literals
set // => [1, 2, 3]
set += [3, 4] // You can concatenate any sequence type to an OrderedSet
set // => [1, 2, 3, 4] (Since 3 was already in the set it was not added again)

Its also recommended that you use the instance methods when possible instead of the global Swift methods for searching an OrderedSet. For example, the Swift.contains(haystack, needle) method will enumerate the OrderedSet instead of making use of the fast lookup implementation that the OrderedSet.contains(needle) method will do.

Be sure to check out the unit tests to see all the different ways to interact with an OrderedSet in action. You can also check out the sample project, which tweaks the default master/detail project to use an OrderedSet instead of an Array.

Installation

OrderedSet is a single Swift file in the Sources directory. You can copy that file into your project, or use via CocoaPods by adding the following line to your Podfile:

pod 'OrderedSet', '5.0'

or use via Carthage by adding

github "Weebly/OrderedSet"

to your Cartfile and embedding the OrderedSet.framework in your app.

And then add the following import where you want to use OrderedSet:

import OrderedSet

Using SwiftPM:

package.append(.package(url: "https://github.com/Weebly/OrderedSet.git", .upToNextMajor(from: "5.0.0")))

License

OrderedSet is available under the MIT license. See the LICENSE file for more info.

CONTRIBUTING

We love to have your help to make OrderedSet better. Feel free to

  • open an issue if you run into any problem.
  • fork the project and submit pull request.
Comments
  • Leverage comparable to maintain order

    Leverage comparable to maintain order

    Breaking change.

    The insert function no longer requires an index. Order is determined by elements.

    Strong influence from SortedArray. Please confirm with Ole if it is ok to use this code, given most of the code is literal copy paste from that project.

        func sorts() {
            let subject = OrderedSet(unsorted: [3, 4, 2, 1], areInIncreasingOrder: <)
            let expected = OrderedSet(sorted: [1, 2, 3, 4])
            XCTAssertEqual(subject, expected)
        }
    
        func insertFront() {
            let subject = OrderedSet(sorted: [1, 2, 3])
            let outcome = subject.insert(0)
            XCTAssertEqual(outcome.index, 0)
            let expected = OrderedSet(sorted: [0, 1, 2, 3])
            XCTAssertEqual(subject, expected)
            XCTAssertTrue(outcome.didInsert)
        }
        
        func insertMiddle() {
            let subject = OrderedSet(sorted: [1, 2, 3])
            let outcome = subject.insert(2)
            XCTAssertEqual(outcome.index, 1)
            let expected = OrderedSet(sorted: [1, 2, 3])
            XCTAssertEqual(subject, expected)
            XCTAssertFalse(outcome.didInsert)
        }
        
        func insertEnd() {
            let subject = OrderedSet(sorted: [1, 2, 3])
            let outcome = subject.insert(4)
            XCTAssertEqual(outcome.index, 3)
            let expected = OrderedSet(sorted: [1, 2, 3, 4])
            XCTAssertEqual(subject, expected)
            XCTAssertTrue(outcome.didInsert)
        }
    
    opened by ghost 5
  • Swift 3 - xCode8b6 support

    Swift 3 - xCode8b6 support

    You know this probably, but she won't compile, I get 75-ish errors, some of which were beyond me to even come close to addressing.

    Do you have a branch somewhere that is compatible?

    I looked here -> swift3 but it's immutable

    Thanx in advance

    opened by wm-j-ray 4
  • Add `removeAllObject(where:)` function in ordered set

    Add `removeAllObject(where:)` function in ordered set

    Hi~ 👋 i want to add removeAllObject(where:) function in ordered set

    removeAllObject(where:) function has simple logic and powerful
    we can use it when want to remove all objects that satisfy the given predicate in the ordered set.
    like Swift.Array.removeAllObject

    i can't waiting your good feedback~😆 thanks

    opened by Woollim 3
  • Make OrderedSet copy-on-write to avoid crashes and spookiness

    Make OrderedSet copy-on-write to avoid crashes and spookiness

    Hello! I'm wondering if making OrderedSet into a proper copy-on-write type is something y'all would consider, and it's totally ok if the answer is "no"!

    We ran into a double-free crash removing the same element from two OrderedSets where the second OrderedSet was made by referring to the first (var newSet = oldSet). See test testRemoveObjects__whenRemovingSameObjectFromTwoSets_doesNotCrash() in this PR. The underlying issue is that each OrderedSet has an array of pointers that point to the same memory addresses, so the second OrderedSet to deallocate that memory will crash.

    At this point, we noticed the copy() method :) That lets us avoid crashing. But it occurred to me that if one OrderedSet can cause another to crash, one OrderedSet can probably mess with another in other fun ways. This is test testSubscriptAssignObjectAtIndex_doesNotAffectOtherSet(), where newSet[0] = "foo" modifies oldSet.

    As a quick fix, I moved sequencedContents into a reference type and got OrderedSet to copy it whenever it's not uniquely referenced. This fixes the issues I found above, and it obviates the copy() method.

    If making OrderedSet copy-on-write like this seems sensible, I'm more than happy to reformat this PR as needed. The main downside I can think of is possibly slower performance, but I admit I have not even attempted to do benchmarks. And it might be cleaner to move most of the logic, as well as the contents dictionary, into the storage class? I'm happy to do that too.

    If y'all aren't interested in this change to OrderedSet, that's totally fair. I don't have any great suggestions for avoiding the double-free crash though, beyond wrapping each pointer in a reference type and ensuring deallocation only happens once. It might be worth considering whether to change OrderedSet to a reference type (i.e. class OrderedSet) and/or to add some documentation that sets don't work the same way as built-in collection types like Array and Dictionary; I suspect we're not the first and won't be the last to have the wrong expectation.

    Thanks!

    opened by nolanw 3
  • Problems with MutableCollection implementation

    Problems with MutableCollection implementation

    Maybe I misunderstand the subscript usage or there are issues with the MutableCollection implementation. The problems arise when using the subscript to set values already contained in the set. Example:

    let set = OrderedSet(sequence: [0, 1, 2])
    print(set)  // [0, 1, 2]
    
    set[1] = 0
    set[2] = 0
    
    print(set.count)  // 1
    print(set)  // [0]
    set.forEach { print($0) }  // 0, 0, 0
    

    Here, the iterator returns repeated values, more than promised by count. I think this example could be resolved just by removing the custom Iterator here and just using the default one.

    However, after digging into it, I found more issues, example:

    let set = OrderedSet(sequence: [0, 1, 2])
    print(set)  // [0, 1, 2]
    
    set[1] = 0
    
    print(set.count)  // 2
    print(set)  // [0, 0]
    set.forEach { print($0) }  // 0, 0, 2
    

    The iterator again returns more than count values but also note that print(set)now contains duplicate values and omits 2!

    The indices for contents and sequencedContents get out of sync. I haven't had time to find the exact issue but there are several problems:

    1. The type of iterator returned
    2. The implementations of startIndex, endIndex, and index(after:)
    3. The subscript setter doesn't/can't protect against already contained values
    opened by arthurhammer 3
  • didSet property observer doesn't work on OrderedSet

    didSet property observer doesn't work on OrderedSet

    Here is my sample code:

    var set = OrderedSet<Int>() {
        didSet {
            print("didSet was called")
        }
    }
    
    set.append(1)
    set.append(2)
    set.append(3)
    

    the print messages is never called and printed event though the set was changed.

    Maybe I am doing this incorrectly. Any advice would help.

    opened by bojanin 2
  • Upgrade to Swift 4

    Upgrade to Swift 4

    Swift 4 has been out for some time now and most libraries have made the transition. Is there a reason why you are keeping the legacy 3.x as the primary branch? If anything Swift 4 should be on master with 3.x on a separate legacy branch.

    opened by BrandonZacharie 2
  • Fix +, - operators (do not mutate the input ordered set)

    Fix +, - operators (do not mutate the input ordered set)

    The current implementation of the + - operators are mutating the input lhs. This contains a fix to avoid mutation.

    Test case:

           let lhs = OrderedSet<Int>()
           let rhs = OrderedSet<Int>(sequence: [1,2])
           
           let sum = lhs + rhs
           print("lhsCount: \(lhs.count), summCount: \(sum.count)") // "lhsCount: 2, summCount: 2" instead of "lhsCount: 0, summCount: 2"
    
    opened by balazsnemeth 2
  • Release memory leftovers from sequencedContents

    Release memory leftovers from sequencedContents

    Added cleaning of allocated memory in case of removing elements from set. Based on Apple documentation and memory graph there is a need to deinitialize object first before being able to deallocate it or we end up with lot of leftovers in memory.

    opened by gKamelo 2
  • add framework targets to enable use with Carthage

    add framework targets to enable use with Carthage

    Hi,

    I added targets to build iOS and macOS frameworks so that OrderedSet can be used via Carthage. Also important to ignore Carthage/ subdirectory. Only app target is now code signed; frameworks don't need this when embedded. Some other fairly standard additions to .gitignore as well.

    These new targets shouldn't affect your podspec, but you might want to check.

    If you accept the pull, please could you also tag a new version (2.0.5), otherwise Carthage will only pull the previous version and won't get the frameworks.

    Cheers!

    opened by t0rst 2
  • Remove conformance to MutableCollection

    Remove conformance to MutableCollection

    According to the documentation, a value stored into a subscript of a MutableCollection instance must subsequently be accessible at that same position. However, setting an OrderedSet subscript may result in a size change operation on the OrderedSet. For example, if we had 1,2,3 in the collection, and did set[2] = 1, the collection becomes 2,1. set[2] is now no longer accessible. There isn't a predictable/clean way to handle this case so I've opted to remove this conformance.

    I've added what in the only method we used from MutableCollection as part of our API.

    Based on comments in issue #9

    opened by ketzusaka 2
  • Support for Codable

    Support for Codable

    Any chance of this supporting Codable? I tried digging in and updating T's generic constraints to be Hashable and Codable (which works fine) but am not familiar enough with UnsafeMutablePointer to know how to have it fit the Codable conformance. I imagine it could just converted in and out as Data but not sure. Thanks!

    opened by cprovatas 1
Owner
Weebly
Weebly
Swift Xid - Xid uses MongoDB Object ID algorighm1 to generate globally unique ids with base32 serialzation to produce shorter strings

Swift Xid - Xid uses MongoDB Object ID algorighm1 to generate globally unique ids with base32 serialzation to produce shorter strings

Uditha Atukorala 0 Jun 13, 2022
Store values using unique, randomly generated identifiers

Storage Store values using unique, randomly generated identifiers. This packages consists of three types: A Storage class, a UniqueIdentifiable protoc

Jordan Baird 1 Feb 23, 2022
Type-Safe Associated Objects in Swift

Type-Safe Associated Objects in Swift TSAO is an implementation of type-safe associated objects in Swift. Objective-C associated objects are useful, b

Lily Ballard 135 Dec 21, 2022
Differific is a diffing tool that helps you compare Hashable objects using the Paul Heckel's diffing algorithm

Differific is a diffing tool that helps you compare Hashable objects using the Paul Heckel's diffing algorithm. Creating a chan

Christoffer Winterkvist 127 Jun 3, 2022
Highlighter will magically find UI objects such as UILabel, UITextView, UITexTfield, UIButton

Highlighter Updates See CHANGELOG for details Intoduction ?? Highlight whatever you want! Highlighter will magically find UI objects such as UILabel,

Kyle Yi 932 Dec 12, 2022
Observe objects in SwiftUI Views which may be nil

ObservedOptionalObject Rationale SwiftUIs @ObservedObject requires that the observed object actually exists. In some cases it's convenient to observe

Matthias Bartelmeß 7 Jul 20, 2022
Getting square objects down round holes

Enough with the bazillion lines of array parsing logic. YOLO. @import YOLOKit; campaigns.reject(^(PPCampaign *campaign){ return campaign.locked;

Max Howell 662 Nov 20, 2022
BFKit-Swift is a collection of useful classes, structs and extensions to develop Apps faster.

Features • Classes and Extensions Compatibility • Requirements • Communication • Contributing • Installing and Usage • Documentation • Changelog • Exa

Fabrizio Brancati 992 Dec 2, 2022
💻 A fast and flexible O(n) difference algorithm framework for Swift collection.

A fast and flexible O(n) difference algorithm framework for Swift collection. The algorithm is optimized based on the Paul Heckel's algorithm. Made wi

Ryo Aoyama 3.3k Jan 4, 2023
A handy collection of more than 500 native Swift extensions to boost your productivity.

SwifterSwift is a collection of over 500 native Swift extensions, with handy methods, syntactic sugar, and performance improvements for wide range of

SwifterSwift 12k Jan 7, 2023
A Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and other native frameworks.

ZamzamKit ZamzamKit is a Swift package for rapid development using a collection of micro utility extensions for Standard Library, Foundation, and othe

Zamzam Inc. 261 Dec 15, 2022
SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

Gymshark 1 Jul 6, 2021
A handy collection of Swift method and Tools to build project faster and more efficient.

SwifterKnife is a collection of Swift extension method and some tools that often use in develop project, with them you might build project faster and

李阳 4 Dec 29, 2022
Array diffs as collection view wants it - now in Swift ✨

Doppelganger-Swift Inspired by Doppelganger written in Swift Features Removes confusion from users when data changes Animates moving, inserting and de

Szymon Maślanka 9 Jul 9, 2019
Collection of native Swift extensions to boost your development. Support tvOS and watchOS.

SparrowKit Collection of native Swift extensions to boost your development. Support iOS, tvOS and watchOS. If you like the project, don't forget to pu

Ivan Vorobei 119 Dec 20, 2022
A Collection of useful Swift property wrappers to make coding easier

Swift Property Wrappers A Collection of useful Swift property wrappers to make c

Gordan Glavaš 2 Jan 28, 2022
Collection of Swift-extensions to boost development process.

SwiftBoost Collection of Swift-extensions to boost development process. Community Installation Ready to use on iOS 13+, tvOS 13+, watchOS 6.0+. Swift

Sparrow Code 119 Dec 20, 2022
Swift package containing collection protocols.

swift-collection-protocols A package containing collection protocols, for the Swift programming language. Overview No overview available. Availability

Alexandre H. Saad 0 Jul 28, 2022
A collection of useful result builders for Swift and Foundation value types

Swift Builders A collection of useful result builders for Swift and Foundation value types. Motivation Arrays, dictionaries, and other collection-base

David Roman 3 Oct 14, 2022