Removing duplicate elements from an array in Swift

I might have an array that looks like the following:

[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

Or, really, any sequence of like-typed portions of data. What I want to do is ensure that there is only one of each identical element. For example, the above array would become:

[1, 4, 2, 6, 24, 15, 60]

Notice that the duplicates of 2, 6, and 15 were removed to ensure that there was only one of each identical element. Does Swift provide a way to do this easily, or will I have to do it myself?

6

48 Answers

12

You can convert to a Set and back to an Array again quite easily:

let unique = Array(Set(originals))

This is not guaranteed to maintain the original order of the array.

15

You can roll your own, e.g. like this:

func unique<S : Sequence, T : Hashable>(source: S) -> [T] where S.Iterator.Element == T { var buffer = [T]() var added = Set<T>() for elem in source { if !added.contains(elem) { buffer.append(elem) added.insert(elem) } } return buffer
}
let vals = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let uniqueVals = uniq(vals) // [1, 4, 2, 6, 24, 15, 60]

And as an extension for Array:

extension Array where Element: Hashable { func uniqued() -> Array { var buffer = Array() var added = Set<Element>() for elem in self { if !added.contains(elem) { buffer.append(elem) added.insert(elem) } } return buffer }
}

Or more elegantly (Swift 4/5):

extension Sequence where Element: Hashable { func uniqued() -> [Element] { var set = Set<Element>() return filter { set.insert($0).inserted } }
}

Which would be used:

[1,2,4,2,1].uniqued() // => [1,2,4]
16

Use a Set or NSOrderedSet to remove duplicates, then convert back to an Array:

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))
5

Swift 4

public extension Array where Element: Hashable { func uniqued() -> [Element] { var seen = Set<Element>() return filter{ seen.insert($0).inserted } }
}

every attempt to insert will also return a tuple: (inserted: Bool, memberAfterInsert: Set.Element). See documentation.

Using the returned value means we can avoid doing more than one loop, so this is O(n).

3

Many answers available here, but I missed this simple extension, suitable for Swift 2 and up:

extension Array where Element:Equatable { func removeDuplicates() -> [Element] { var result = [Element]() for value in self { if result.contains(value) == false { result.append(value) } } return result }
}

Makes it super simple. Can be called like this:

let arrayOfInts = [2, 2, 4, 4]
print(arrayOfInts.removeDuplicates()) // Prints: [2, 4]

Filtering based on properties

To filter an array based on properties, you can use this method:

extension Array { func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{ var results = [Element]() forEach { (element) in let existingElements = results.filter { return includeElement(lhs: element, rhs: $0) } if existingElements.count == 0 { results.append(element) } } return results }
}

Which you can call as followed:

let filteredElements = myElements.filterDuplicates { $0.PropertyOne == $1.PropertyOne && $0.PropertyTwo == $1.PropertyTwo }
5

If you put both extensions in your code, the faster Hashable version will be used when possible, and the Equatable version will be used as a fallback.

public extension Sequence where Element: Hashable { /// The elements of the sequence, with duplicates removed. /// - Note: Has equivalent elements to `Set(self)`. @available( swift, deprecated: 5.4, message: "Doesn't compile without the constant in Swift 5.3." ) var firstUniqueElements: [Element] { let getSelf: (Element) -> Element = \.self return firstUniqueElements(getSelf) }
}
public extension Sequence where Element: Equatable { /// The elements of the sequence, with duplicates removed. /// - Note: Has equivalent elements to `Set(self)`. @available( swift, deprecated: 5.4, message: "Doesn't compile without the constant in Swift 5.3." ) var firstUniqueElements: [Element] { let getSelf: (Element) -> Element = \.self return firstUniqueElements(getSelf) }
}
public extension Sequence { /// The elements of the sequences, with "duplicates" removed /// based on a closure. func firstUniqueElements<Hashable: Swift.Hashable>( _ getHashable: (Element) -> Hashable ) -> [Element] { var set: Set<Hashable> = [] return filter { set.insert(getHashable($0)).inserted } } /// The elements of the sequence, with "duplicates" removed, /// based on a closure. func firstUniqueElements<Equatable: Swift.Equatable>( _ getEquatable: (Element) -> Equatable ) -> [Element] { reduce(into: []) { uniqueElements, element in if zip( uniqueElements.lazy.map(getEquatable), AnyIterator { [equatable = getEquatable(element)] in equatable } ).allSatisfy(!=) { uniqueElements.append(element) } } }
}

If order isn't important, then you can always just use this Set initializer.

9

edit/update Swift 4 or later

We can also extend RangeReplaceableCollection protocol to allow it to be used with StringProtocol types as well:

extension RangeReplaceableCollection where Element: Hashable { var orderedSet: Self { var set = Set<Element>() return filter { set.insert($0).inserted } } mutating func removeDuplicates() { var set = Set<Element>() removeAll { !set.insert($0).inserted } }
}

let integers = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let integersOrderedSet = integers.orderedSet // [1, 4, 2, 6, 24, 15, 60]

"abcdefabcghi".orderedSet // "abcdefghi"
"abcdefabcghi".dropFirst(3).orderedSet // "defabcghi"

Mutating method:

var string = "abcdefabcghi"
string.removeDuplicates()
string // "abcdefghi"
var substring = "abcdefabcdefghi".dropFirst(3) // "defabcdefghi"
substring.removeDuplicates()
substring // "defabcghi"

For Swift 3 click here

16

Swift 4

Guaranteed to keep ordering.

extension Array where Element: Equatable { func removingDuplicates() -> Array { return reduce(into: []) { result, element in if !result.contains(element) { result.append(element) } } }
}
8

Inspired by , we can declare a more powerful tool that is able to filter for unicity on any keyPath. Thanks to Alexander comments on various answers regarding complexity, the below solutions should be near optimal.

Non-mutating solution

We extend with a function that is able to filter for unicity on any keyPath:

extension RangeReplaceableCollection { /// Returns a collection containing, in order, the first instances of /// elements of the sequence that compare equally for the keyPath. func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> Self { var unique = Set<T>() return filter { unique.insert($0[keyPath: keyPath]).inserted } }
}

Note: in the case where your object doesn't conform to RangeReplaceableCollection, but does conform to Sequence, you can have this additional extension, but the return type will always be an Array:

extension Sequence { /// Returns an array containing, in order, the first instances of /// elements of the sequence that compare equally for the keyPath. func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> [Element] { var unique = Set<T>() return filter { unique.insert($0[keyPath: keyPath]).inserted } }
}

Usage

If we want unicity for elements themselves, as in the question, we use the keyPath \.self:

let a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let b = a.unique(for: \.self)
/* b is [1, 4, 2, 6, 24, 15, 60] */

If we want unicity for something else (like for the id of a collection of objects) then we use the keyPath of our choice:

let a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
let b = a.unique(for: \.y)
/* b is [{x 1 y 1}, {x 1 y 2}] */

Mutating solution

We extend with a mutating function that is able to filter for unicity on any keyPath:

extension RangeReplaceableCollection { /// Keeps only, in order, the first instances of /// elements of the collection that compare equally for the keyPath. mutating func uniqueInPlace<T: Hashable>(for keyPath: KeyPath<Element, T>) { var unique = Set<T>() removeAll { !unique.insert($0[keyPath: keyPath]).inserted } }
}

Usage

If we want unicity for elements themselves, as in the question, we use the keyPath \.self:

var a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
a.uniqueInPlace(for: \.self)
/* a is [1, 4, 2, 6, 24, 15, 60] */

If we want unicity for something else (like for the id of a collection of objects) then we use the keyPath of our choice:

var a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
a.uniqueInPlace(for: \.y)
/* a is [{x 1 y 1}, {x 1 y 2}] */
7

Here's a category on SequenceType which preserves the original order of the array, but uses a Set to do the contains lookups to avoid the O(n) cost on Array's contains(_:) method.

public extension Sequence where Element: Hashable { /// Return the sequence with all duplicates removed. /// /// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]` /// /// - note: Taken from as /// per @Alexander's comment. func uniqued() -> [Element] { var seen = Set<Element>() return self.filter { seen.insert($0).inserted } }
}

If you aren't Hashable or Equatable, you can pass in a predicate to do the equality check:

extension Sequence { /// Return the sequence with all duplicates removed. /// /// Duplicate, in this case, is defined as returning `true` from `comparator`. /// /// - note: Taken from func uniqued(comparator: @escaping (Element, Element) throws -> Bool) rethrows -> [Element] { var buffer: [Element] = [] for element in self { // If element is already in buffer, skip to the next element if try buffer.contains(where: { try comparator(element, $0) }) { continue } buffer.append(element) } return buffer }
}

Now, if you don't have Hashable, but are Equatable, you can use this method:

extension Sequence where Element: Equatable { /// Return the sequence with all duplicates removed. /// /// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]` /// /// - note: Taken from func uniqued() -> [Element] { return self.uniqued(comparator: ==) }
}

Finally, you can add a key path version of uniqued like this:

extension Sequence { /// Returns the sequence with duplicate elements removed, performing the comparison using the property at /// the supplied keypath. /// /// i.e. /// /// /// [ /// MyStruct(value: "Hello"), /// MyStruct(value: "Hello"), /// MyStruct(value: "World") /// ].uniqued(\.value) /// /// would result in /// /// /// [ /// MyStruct(value: "Hello"), /// MyStruct(value: "World") /// ] /// /// /// - note: Taken from /// func uniqued<T: Equatable>(_ keyPath: KeyPath<Element, T>) -> [Element] { self.uniqued { $0[keyPath: keyPath] == $1[keyPath: keyPath] } }
}

You can stick both of these into your app, Swift will choose the right one depending on your sequence's Iterator.Element type.


For El Capitan, you can extend this method to include multiple keypaths like this:

 /// Returns the sequence with duplicate elements removed, performing the comparison using the property at /// the supplied keypaths. /// /// i.e. /// /// /// [ /// MyStruct(value1: "Hello", value2: "Paula"), /// MyStruct(value1: "Hello", value2: "Paula"), /// MyStruct(value1: "Hello", value2: "Bean"), /// MyStruct(value1: "World", value2: "Sigh") /// ].uniqued(\.value1, \.value2) /// /// would result in /// /// /// [ /// MyStruct(value1: "Hello", value2: "Paula"), /// MyStruct(value1: "Hello", value2: "Bean"), /// MyStruct(value1: "World", value2: "Sigh") /// ] /// /// /// - note: Taken from /// func uniqued<T: Equatable, U: Equatable>(_ keyPath1: KeyPath<Element, T>, _ keyPath2: KeyPath<Element, U>) -> [Element] { self.uniqued { $0[keyPath: keyPath1] == $1[keyPath: keyPath1] && $0[keyPath: keyPath2] == $1[keyPath: keyPath2] } }

but (imho) you're probably better off just passing in your own block to self.uniqued.

5

Swift 5

extension Sequence where Element: Hashable { func unique() -> [Element] { NSOrderedSet(array: self as! [Any]).array as! [Element] }
}
4

Think like a functional programmer :)

To filter the list based on whether the element has already occurred, you need the index. You can use enumerated to get the index and map to return to the list of values.

let unique = myArray .enumerated() .filter{ myArray.firstIndex(of: $0.1) == $0.0 } .map{ $0.1 }

This guarantees the order. If you don't mind about the order then the existing answer of Array(Set(myArray)) is simpler and probably more efficient.


UPDATE: Some notes on efficiency and correctness

A few people have commented on the efficiency. I'm definitely in the school of writing correct and simple code first and then figuring out bottlenecks later, though I appreciate it's debatable whether this is clearer than Array(Set(array)).

This method is a lot slower than Array(Set(array)). As noted in comments, it does preserve order and works on elements that aren't Hashable.

However, @Alain T's method also preserves order and is also a lot faster. So unless your element type is not hashable, or you just need a quick one liner, then I'd suggest going with their solution.

Here are a few tests on a MacBook Pro (2014) on Xcode 11.3.1 (Swift 5.1) in Release mode.

The profiler function and two methods to compare:

func printTimeElapsed(title:String, operation:()->()) { var totalTime = 0.0 for _ in (0..<1000) { let startTime = CFAbsoluteTimeGetCurrent() operation() let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime totalTime += timeElapsed } let meanTime = totalTime / 1000 print("Mean time for \(title): \(meanTime) s")
}
func method1<T: Hashable>(_ array: Array<T>) -> Array<T> { return Array(Set(array))
}
func method2<T: Equatable>(_ array: Array<T>) -> Array<T>{ return array .enumerated() .filter{ array.firstIndex(of: $0.1) == $0.0 } .map{ $0.1 }
}
// Alain T.'s answer (adapted)
func method3<T: Hashable>(_ array: Array<T>) -> Array<T> { var uniqueKeys = Set<T>() return array.filter{uniqueKeys.insert($0).inserted}
}

And a small variety of test inputs:

func randomString(_ length: Int) -> String { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0..<length).map{ _ in letters.randomElement()! })
}
let shortIntList = (0..<100).map{_ in Int.random(in: 0..<100) }
let longIntList = (0..<10000).map{_ in Int.random(in: 0..<10000) }
let longIntListManyRepetitions = (0..<10000).map{_ in Int.random(in: 0..<100) }
let longStringList = (0..<10000).map{_ in randomString(1000)}
let longMegaStringList = (0..<10000).map{_ in randomString(10000)}

Gives as output:

Mean time for method1 on shortIntList: 2.7358531951904296e-06 s
Mean time for method2 on shortIntList: 4.910230636596679e-06 s
Mean time for method3 on shortIntList: 6.417632102966309e-06 s
Mean time for method1 on longIntList: 0.0002518167495727539 s
Mean time for method2 on longIntList: 0.021718120217323302 s
Mean time for method3 on longIntList: 0.0005312927961349487 s
Mean time for method1 on longIntListManyRepetitions: 0.00014377200603485108 s
Mean time for method2 on longIntListManyRepetitions: 0.0007293639183044434 s
Mean time for method3 on longIntListManyRepetitions: 0.0001843773126602173 s
Mean time for method1 on longStringList: 0.007168249964714051 s
Mean time for method2 on longStringList: 0.9114790915250778 s
Mean time for method3 on longStringList: 0.015888616919517515 s
Mean time for method1 on longMegaStringList: 0.0525397013425827 s
Mean time for method2 on longMegaStringList: 1.111266262292862 s
Mean time for method3 on longMegaStringList: 0.11214958941936493 s
12

One more Swift 3.0 solution to remove duplicates from an array. This solution improves on many other solutions already proposed by:

  • Preserving the order of the elements in the input array
  • Linear complexity O(n): single pass filter O(n) + set insertion O(1)

Given the integer array:

let numberArray = [10, 1, 2, 3, 2, 1, 15, 4, 5, 6, 7, 3, 2, 12, 2, 5, 5, 6, 10, 7, 8, 3, 3, 45, 5, 15, 6, 7, 8, 7]

Functional code:

func orderedSet<T: Hashable>(array: Array<T>) -> Array<T> { var unique = Set<T>() return array.filter { element in return unique.insert(element).inserted }
}
orderedSet(array: numberArray) // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]

Array extension code:

extension Array where Element:Hashable { var orderedSet: Array { var unique = Set<Element>() return filter { element in return unique.insert(element).inserted } }
}
numberArray.orderedSet // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]

This code takes advantage of the result returned by the insert operation on Set, which executes on O(1), and returns a tuple indicating if the item was inserted or if it already existed in the set.

If the item was in the set, filter will exclude it from the final result.

4

An alternate (if not optimal) solution from here using immutable types rather than variables:

func deleteDuplicates<S: ExtensibleCollectionType where S.Generator.Element: Equatable>(seq:S)-> S { let s = reduce(seq, S()){ ac, x in contains(ac,x) ? ac : ac + [x] } return s
}

Included to contrast Jean-Pillippe's imperative approach with a functional approach.

As a bonus this function works with strings as well as arrays!

Edit: This answer was written in 2014 for Swift 1.0 (before Set was available in Swift). It doesn't require Hashable conformance & runs in quadratic time.

2

swift 2

with uniq function answer:

func uniq<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] { var seen: [E:Bool] = [:] return source.filter({ (v) -> Bool in return seen.updateValue(true, forKey: v) == nil })
}

use:

var test = [1,2,3,4,5,6,7,8,9,9,9,9,9,9]
print(uniq(test)) //1,2,3,4,5,6,7,8,9
1

Swift 4.x:

extension Sequence where Iterator.Element: Hashable { func unique() -> [Iterator.Element] { return Array(Set<Iterator.Element>(self)) } func uniqueOrdered() -> [Iterator.Element] { return reduce([Iterator.Element]()) { $0.contains($1) ? $0 : $0 + [$1] } }
}

usage:

["Ljubljana", "London", "Los Angeles", "Ljubljana"].unique()

or

["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()
1

In Swift 5

 var array: [String] = ["Aman", "Sumit", "Aman", "Sumit", "Mohan", "Mohan", "Amit"] let uniq = Array(Set(array)) print(uniq)

Output Will be

 ["Sumit", "Mohan", "Amit", "Aman"]
1

For arrays where the elements are neither Hashable nor Comparable (e.g. complex objects, dictionaries or structs), this extension provides a generalized way to remove duplicates:

extension Array
{ func filterDuplicate<T:Hashable>(_ keyValue:(Element)->T) -> [Element] { var uniqueKeys = Set<T>() return filter{uniqueKeys.insert(keyValue($0)).inserted} } func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element] { return filterDuplicate{"\(keyValue($0))"} }
}
// example usage: (for a unique combination of attributes):
peopleArray = peopleArray.filterDuplicate{ ($0.name, $0.age, $0.sex) }
or...
peopleArray = peopleArray.filterDuplicate{ "\(($0.name, $0.age, $0.sex))" }

You don't have to bother with making values Hashable and it allows you to use different combinations of fields for uniqueness.

Note: for a more robust approach, please see the solution proposed by Coeur in the comments below.

[EDIT] Swift 4 alternative

With Swift 4.2 you can use the Hasher class to build a hash much easier. The above extension could be changed to leverage this :

extension Array
{ func filterDuplicate(_ keyValue:((AnyHashable...)->AnyHashable,Element)->AnyHashable) -> [Element] { func makeHash(_ params:AnyHashable ...) -> AnyHashable { var hash = Hasher() params.forEach{ hash.combine($0) } return hash.finalize() } var uniqueKeys = Set<AnyHashable>() return filter{uniqueKeys.insert(keyValue(makeHash,$0)).inserted} }
}

The calling syntax is a little different because the closure receives an additional parameter containing a function to hash a variable number of values (which must be Hashable individually)

peopleArray = peopleArray.filterDuplicate{ $0($1.name, $1.age, $1.sex) } 

It will also work with a single uniqueness value (using $1 and ignoring $0).

peopleArray = peopleArray.filterDuplicate{ $1.name } 
5

No need to write extensions now.

Apple has finally introduced uniqued() method in its Algorithms package and can be used on any type conforming to Sequence protocol.

import Algorithms
let numbers = [1, 2, 3, 3, 2, 3, 3, 2, 2, 2, 1]
print(numbers.uniqued()) // prints [1, 2, 3]

More info

3

As was noted at WWDC 2021, Swift has community-developed Algorithms, Collections, and Numerics Packages. The Algorithms package features a uniqued() algorithm.

These are not yet part of the Swift Standard library. You can currently download them from Apple's Github page and/or install them via Swift Package Manager.

WWDC Video:

Github page:

uniqued() and uniqued(on:) documentation:

1
  1. First add all the elements of an array to NSOrderedSet.
  2. This will remove all the duplicates in your array.
  3. Again convert this orderedset to an array.

Done....

Example

let array = [1,1,1,1,2,2,2,2,4,6,8]
let orderedSet : NSOrderedSet = NSOrderedSet(array: array)
let arrayWithoutDuplicates : NSArray = orderedSet.array as NSArray

output of arrayWithoutDuplicates - [1,2,4,6,8]

You can use directly a set collection to remove duplicate, then cast it back to an array

var myArray = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
var mySet = Set<Int>(myArray)
myArray = Array(mySet) // [2, 4, 60, 6, 15, 24, 1]

Then you can order your array as you want

myArray.sort{$0 < $1} // [1, 2, 4, 6, 15, 24, 60]
1

In case you need values sorted, this works (Swift 4)

let sortedValues = Array(Set(array)).sorted()

8

Here is a solution that

  • Uses no legacy NS types
  • Is reasonably fast with O(n)
  • Is concise
  • Preserves element order
extension Array where Element: Hashable { var uniqueValues: [Element] { var allowed = Set(self) return compactMap { allowed.remove($0) } }
}
1

Slightly more succinct syntax version of Daniel Krom's Swift 2 answer, using a trailing closure and shorthand argument name, which appears to be based on Airspeed Velocity's original answer:

func uniq<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] { var seen = [E: Bool]() return source.filter { seen.updateValue(true, forKey: $0) == nil }
}

Example of implementing a custom type that can be used with uniq(_:) (which must conform to Hashable, and thus Equatable, because Hashable extends Equatable):

func ==(lhs: SomeCustomType, rhs: SomeCustomType) -> Bool { return lhs.id == rhs.id // && lhs.someOtherEquatableProperty == rhs.someOtherEquatableProperty
}
struct SomeCustomType { let id: Int // ...
}
extension SomeCustomType: Hashable { var hashValue: Int { return id }
}

In the above code...

id, as used in the overload of ==, could be any Equatable type (or method that returns an Equatable type, e.g., someMethodThatReturnsAnEquatableType()). The commented-out code demonstrates extending the check for equality, where someOtherEquatableProperty is another property of an Equatable type (but could also be a method that returns an Equatable type).

id, as used in the hashValue computed property (required to conform to Hashable), could be any Hashable (and thus Equatable) property (or method that returns a Hashable type).

Example of using uniq(_:):

var someCustomTypes = [SomeCustomType(id: 1), SomeCustomType(id: 2), SomeCustomType(id: 3), SomeCustomType(id: 1)]
print(someCustomTypes.count) // 4
someCustomTypes = uniq(someCustomTypes)
print(someCustomTypes.count) // 3
1

here I've done some O(n) solution for objects. Not few-lines solution, but...

struct DistinctWrapper <T>: Hashable { var underlyingObject: T var distinctAttribute: String var hashValue: Int { return distinctAttribute.hashValue }
}
func distinct<S : SequenceType, T where S.Generator.Element == T>(source: S, distinctAttribute: (T) -> String, resolution: (T, T) -> T) -> [T] { let wrappers: [DistinctWrapper<T>] = source.map({ return DistinctWrapper(underlyingObject: $0, distinctAttribute: distinctAttribute($0)) }) var added = Set<DistinctWrapper<T>>() for wrapper in wrappers { if let indexOfExisting = added.indexOf(wrapper) { let old = added[indexOfExisting] let winner = resolution(old.underlyingObject, wrapper.underlyingObject) added.insert(DistinctWrapper(underlyingObject: winner, distinctAttribute: distinctAttribute(winner))) } else { added.insert(wrapper) } } return Array(added).map( { return $0.underlyingObject } )
}
func == <T>(lhs: DistinctWrapper<T>, rhs: DistinctWrapper<T>) -> Bool { return lhs.hashValue == rhs.hashValue
}
// tests
// case : perhaps we want to get distinct addressbook list which may contain duplicated contacts like Irma and Irma Burgess with same phone numbers
// solution : definitely we want to exclude Irma and keep Irma Burgess
class Person { var name: String var phoneNumber: String init(_ name: String, _ phoneNumber: String) { self.name = name self.phoneNumber = phoneNumber }
}
let persons: [Person] = [Person("Irma Burgess", "11-22-33"), Person("Lester Davidson", "44-66-22"), Person("Irma", "11-22-33")]
let distinctPersons = distinct(persons, distinctAttribute: { (person: Person) -> String in return person.phoneNumber }, resolution: { (p1, p2) -> Person in return p1.name.characters.count > p2.name.characters.count ? p1 : p2 }
)
// distinctPersons contains ("Irma Burgess", "11-22-33") and ("Lester Davidson", "44-66-22")
1

I used @Jean-Philippe Pellet's answer and made an Array extension that does set-like operations on arrays, while maintaining the order of elements.

/// Extensions for performing set-like operations on lists, maintaining order
extension Array where Element: Hashable { func unique() -> [Element] { var seen: [Element:Bool] = [:] return self.filter({ seen.updateValue(true, forKey: $0) == nil }) } func subtract(takeAway: [Element]) -> [Element] { let set = Set(takeAway) return self.filter({ !set.contains($0) }) } func intersect(with: [Element]) -> [Element] { let set = Set(with) return self.filter({ set.contains($0) }) }
}
1

This is just a very simple and convenient implementation. A computed property in an extension of an Array that has equatable elements.

extension Array where Element: Equatable { /// Array containing only _unique_ elements. var unique: [Element] { var result: [Element] = [] for element in self { if !result.contains(element) { result.append(element) } } return result }
}
1
func removeDublicate (ab: [Int]) -> [Int] {
var answer1:[Int] = []
for i in ab { if !answer1.contains(i) { answer1.append(i) }}
return answer1
}

Usage:

let f = removeDublicate(ab: [1,2,2])
print(f)
3

Swift 3/ Swift 4/ Swift 5

Just one line code to omit Array duplicates without effecting order:

let filteredArr = Array(NSOrderedSet(array: yourArray))
1 12

You Might Also Like