Unique objects inside the Swift array

I have an array with custom objects.

I would like to put repeating objects with repeating properties:

let product = Product() product.subCategory = "one" let product2 = Product() product2.subCategory = "two" let product3 = Product() product3.subCategory = "two" let array = [product,product2,product3] 

in this case, click product2 or product3

+5
source share
5 answers

You can use the Swift Set :

 let array = [product,product2,product3] let set = Set(array) 

You have to make Product conform to Hashable (and therefore Equatable ), though:

 class Product : Hashable { var subCategory = "" var hashValue: Int { return subCategory.hashValue } } func ==(lhs: Product, rhs: Product) -> Bool { return lhs.subCategory == rhs.subCategory } 

And if Product was a subclass of NSObject , you should override isEqual :

 override func isEqual(object: AnyObject?) -> Bool { if let product = object as? Product { return product == self } else { return false } } 

Obviously, change those that reflect other properties that you might have in your class. For instance:

 class Product : Hashable { var category = "" var subCategory = "" var hashValue: Int { return [category, subCategory].hashValue } } func ==(lhs: Product, rhs: Product) -> Bool { return lhs.category == rhs.category && lhs.subCategory == rhs.subCategory } 
+6
source

Here is the array extension to return a unique list of objects based on a given key:

 extension Array { func unique<T:Hashable>(map: ((Element) -> (T))) -> [Element] { var set = Set<T>() //the unique list kept in a Set for fast retrieval var arrayOrdered = [Element]() //keeping the unique list of elements but ordered for value in self { if !set.contains(map(value)) { set.insert(map(value)) arrayOrdered.append(value) } } return arrayOrdered } } 

using this you can do it

 let unique = [product,product2,product3].unique{$0.subCategory} 

this has the advantage of not requiring a hashable and can return a unique list based on any field or combination

+3
source

If Product matches Equatable , where the product is equally based on its subcategory (and you don't care about order), you can add objects to the set and take an array from this set:

 let array = [product,product2,product3] let set = NSSet(array: array) let uniqueArray = set.allObjects 

or

 let array = [product,product2,product3] let set = Set(array) let uniqueArray = Array(set) 
+1
source
 class Product { var subCategory: String = "" } let product = Product() product.subCategory = "one" let product2 = Product() product2.subCategory = "two" let product3 = Product() product3.subCategory = "two" let array = [product,product2,product3] extension Product : Hashable { var hashValue: Int { return subCategory.hashValue } } func ==(lhs: Product, rhs: Product)->Bool { return lhs.subCategory == rhs.subCategory } let set = Set(array) set.forEach { (p) -> () in print(p, p.subCategory) } /* Product one Product two */ 

if the element is part of the set or not, does not depend on hashValue, it depends on comparison. If your product is Hashable, it must be Equatable. if you want the creation of a collection to depend entirely on a subcategory, the comparison should depend entirely on a subcategory. this can be a big problem if you need to compare your products differently.

+1
source

If your class conforms to the Hashable protocol and you want to keep the original order of the array, you can create an extension as follows:

 extension Array where Element: Hashable { var uniqueElements: [Element] { var elements: [Element] = [] for element in self { if let _ = elements.indexOf(element) { print("item found") } else { print("item not found, add it") elements.append(element) } } return elements } } 
+1
source

Source: https://habr.com/ru/post/1236574/


All Articles