extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
However, I get an error on var index = find(self, object)
'T' is not convertible to 'T'
I also tried with this method signature: func removeObject(object: AnyObject), however, I get the same error:
'AnyObject' is not convertible to 'T'
What is the proper way to do this?
As of Swift 2, this can be achieved with a protocol extension method.
removeObject() is defined as a method on all types conforming
to RangeReplaceableCollectionType (in particular on Array) if
the elements of the collection are Equatable:
extension RangeReplaceableCollectionType where Generator.Element : Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func removeObject(object : Generator.Element) {
if let index = self.indexOf(object) {
self.removeAtIndex(index)
}
}
}
Example:
var ar = [1, 2, 3, 2]
ar.removeObject(2)
print(ar) // [1, 3, 2]
Update for Swift 2 / Xcode 7 beta 2: As Airspeed Velocity noticed
in the comments, it is now actually possible to write a method on a generic type that is more restrictive on the template, so the method
could now actually be defined as an extension of Array:
extension Array where Element : Equatable {
// ... same method as above ...
}
The protocol extension still has the advantage of being applicable to
a larger set of types.
Update for Swift 3:
extension Array where Element: Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func remove(object: Element) {
if let index = index(of: object) {
remove(at: index)
}
}
}
Update for Swift 5:
extension Array where Element: Equatable {
/// Remove first collection element that is equal to the given `object` or `element`:
mutating func remove(element: Element) {
if let index = firstIndex(of: element) {
remove(at: index)
}
}
}
You cannot write a method on a generic type that is more restrictive on the template.
NOTE: as of Swift 2.0, you can now write methods that are more restrictive on the template. If you have upgraded your code to 2.0, see other answers further down for new options to implement this using extensions.
The reason you get the error 'T' is not convertible to 'T' is that you are actually defining a new T in your method that is not related at all to the original T. If you wanted to use T in your method, you can do so without specifying it on your method.
The reason that you get the second error 'AnyObject' is not convertible to 'T' is that all possible values for T are not all classes. For an instance to be converted to AnyObject, it must be a class (it cannot be a struct, enum, etc.).
Your best bet is to make it a function that accepts the array as an argument:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}
Or instead of modifying the original array, you can make your method more thread safe and reusable by returning a copy:
func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}
As an alternative that I don't recommend, you can have your method fail silently if the type stored in the array cannot be converted to the the methods template (that is equatable). (For clarity, I am using U instead of T for the method's template):
extension Array {
mutating func removeObject<U: Equatable>(object: U) {
var index: Int?
for (idx, objectToCompare) in enumerate(self) {
if let to = objectToCompare as? U {
if object == to {
index = idx
}
}
}
if(index != nil) {
self.removeAtIndex(index!)
}
}
}
var list = [1,2,3]
list.removeObject(2) // Successfully removes 2 because types matched
list.removeObject("3") // fails silently to remove anything because the types don't match
list // [1, 3]
Edit To overcome the silent failure you can return the success as a bool:
extension Array {
mutating func removeObject<U: Equatable>(object: U) -> Bool {
for (idx, objectToCompare) in self.enumerate() { //in old swift use enumerate(self)
if let to = objectToCompare as? U {
if object == to {
self.removeAtIndex(idx)
return true
}
}
}
return false
}
}
var list = [1,2,3,2]
list.removeObject(2)
list
list.removeObject(2)
list
briefly and concisely:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T])
{
var index = find(array, object)
array.removeAtIndex(index!)
}
After reading all the above, to my mind the best answer is:
func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] {
return fromArray.filter { return $0 != object }
}
Sample:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = arrayRemovingObject("Cat", fromArray:myArray )
Swift 2 (xcode 7b4) array extension:
extension Array where Element: Equatable {
func arrayRemovingObject(object: Element) -> [Element] {
return filter { $0 != object }
}
}
Sample:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = myArray.arrayRemovingObject("Cat" )
Swift 3.1 update
Came back to this now that Swift 3.1 is out. Below is an extension which provides exhaustive, fast, mutating and creating variants.
extension Array where Element:Equatable {
public mutating func remove(_ item:Element ) {
var index = 0
while index < self.count {
if self[index] == item {
self.remove(at: index)
} else {
index += 1
}
}
}
public func array( removing item:Element ) -> [Element] {
var result = self
result.remove( item )
return result
}
}
Samples:
// Mutation...
var array1 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
array1.remove("Cat")
print(array1) // ["Dog", "Turtle", "Socks"]
// Creation...
let array2 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
let array3 = array2.array(removing:"Cat")
print(array3) // ["Dog", "Turtle", "Fish"]
With protocol extensions you can do this,
extension Array where Element: Equatable {
mutating func remove(object: Element) {
if let index = indexOf({ $0 == object }) {
removeAtIndex(index)
}
}
}
Same functionality for classes,
Swift 2
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = indexOf({ $0 === object }) {
removeAtIndex(index)
}
}
}
Swift 3
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = index(where: { $0 === object }) {
remove(at: index)
}
}
}
But if a class implements Equatable it becomes ambiguous and the compiler gives an throws an error.
With using protocol extensions in swift 2.0
extension _ArrayType where Generator.Element : Equatable{
mutating func removeObject(object : Self.Generator.Element) {
while let index = self.indexOf(object){
self.removeAtIndex(index)
}
}
}
what about to use filtering? the following works quite well even with [AnyObject].
import Foundation
extension Array {
mutating func removeObject<T where T : Equatable>(obj: T) {
self = self.filter({$0 as? T != obj})
}
}
Maybe I didn't understand the question.
Why wouldn't this work?
import Foundation
extension Array where Element: Equatable {
mutating func removeObject(object: Element) {
if let index = self.firstIndex(of: object) {
self.remove(at: index)
}
}
}
var testArray = [1,2,3,4,5,6,7,8,9,0]
testArray.removeObject(object: 6)
let newArray = testArray
var testArray2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
testArray2.removeObject(object: "6")
let newArray2 = testArray2
No need to extend:
var ra = [7, 2, 5, 5, 4, 5, 3, 4, 2]
print(ra) // [7, 2, 5, 5, 4, 5, 3, 4, 2]
ra.removeAll(where: { $0 == 5 })
print(ra) // [7, 2, 4, 3, 4, 2]
if let i = ra.firstIndex(of: 4) {
ra.remove(at: i)
}
print(ra) // [7, 2, 3, 4, 2]
if let j = ra.lastIndex(of: 2) {
ra.remove(at: j)
}
print(ra) // [7, 2, 3, 4]
There is another possibility of removing an item from an array without having possible unsafe usage, as the generic type of the object to remove cannot be the same as the type of the array. Using optionals is also not the perfect way to go as they are very slow. You could therefore use a closure like it is already used when sorting an array for example.
//removes the first item that is equal to the specified element
mutating func removeFirst(element: Element, equality: (Element, Element) -> Bool) -> Bool {
for (index, item) in enumerate(self) {
if equality(item, element) {
self.removeAtIndex(index)
return true
}
}
return false
}
When you extend the Array class with this function you can remove elements by doing the following:
var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { $0 == $1 } //Banana is now removed
However you could even remove an element only if it has the same memory address (only for classes conforming to AnyObject protocol, of course):
let date1 = NSDate()
let date2 = NSDate()
var array = [date1, date2]
array.removeFirst(NSDate()) { $0 === $1 } //won't do anything
array.removeFirst(date1) { $0 === $1 } //array now contains only 'date2'
The good thing is, that you can specify the parameter to compare. For example when you have an array of arrays, you can specify the equality closure as { $0.count == $1.count } and the first array having the same size as the one to remove is removed from the array.
You could even shorten the function call by having the function as mutating func removeFirst(equality: (Element) -> Bool) -> Bool, then replace the if-evaluation with equality(item) and call the function by array.removeFirst({ $0 == "Banana" }) for example.
Using indexOf instead of a for or enumerate:
extension Array where Element: Equatable {
mutating func removeElement(element: Element) -> Element? {
if let index = indexOf(element) {
return removeAtIndex(index)
}
return nil
}
mutating func removeAllOccurrencesOfElement(element: Element) -> Int {
var occurrences = 0
while true {
if let index = indexOf(element) {
removeAtIndex(index)
occurrences++
} else {
return occurrences
}
}
}
}
I finally ended up with following code.
extension Array where Element: Equatable {
mutating func remove<Element: Equatable>(item: Element) -> Array {
self = self.filter { $0 as? Element != item }
return self
}
}
Your problem is T is not related to the type of your array in anyway for example you could have
var array = [1,2,3,4,5,6]
array.removeObject(object:"four")
"six" is Equatable, but its not a type that can be compared to Integer, if you change it to
var array = [1,2,3,4,5,6]
extension Array where Element : Equatable {
mutating func removeObject(object: Element) {
filter { $0 != object }
}
}
array.removeObject(object:"four")
it now produces an error on calling removeObject for the obvious reason its not an array of strings, to remove 4 you can just
array.removeObject(object:4)
Other problem you have is its a self modifying struct so the method has to be labeled as so and your reference to it at the top has to be a var
Implementation in Swift 2:
extension Array {
mutating func removeObject<T: Equatable>(object: T) -> Bool {
var index: Int?
for (idx, objectToCompare) in self.enumerate() {
if let toCompare = objectToCompare as? T {
if toCompare == object {
index = idx
break
}
}
}
if(index != nil) {
self.removeAtIndex(index!)
return true
} else {
return false
}
}
}
I was able to get it working with:
extension Array {
mutating func removeObject<T: Equatable>(object: T) {
var index: Int?
for (idx, objectToCompare) in enumerate(self) {
let to = objectToCompare as T
if object == to {
index = idx
}
}
if(index) {
self.removeAtIndex(index!)
}
}
}
Related
In my application I added one object in array when select cell and unselect and remove object when re-select cell. I used that code but give me error.
extension Array {
func indexOfObject(object : AnyObject) -> NSInteger {
return (self as NSArray).indexOfObject(object)
}
mutating func removeObject(object : AnyObject) {
for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) {
self.removeAtIndex(index)
}
}
}
class MyViewController: UITableViewController {
var arrContacts: [Any] = []
var contacts: [Any] = []
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
arrContacts.removeObject(contacts[indexPath.row])
}
}
It gives me 2 error like that:
C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'
The Swift equivalent to NSMutableArray's removeObject is:
var array = ["alpha", "beta", "gamma"]
if let index = array.firstIndex(of: "beta") {
array.remove(at: index)
}
if the objects are unique. There is no need at all to cast to NSArray and use indexOfObject:
The API index(of: also works but this causes an unnecessary implicit bridge cast to NSArray.
Of course you can write an extension of RangeReplaceableCollection to emulate the function. But due to value semantics you cannot name it removeObject.
extension RangeReplaceableCollection where Element : Equatable {
#discardableResult
mutating func remove(_ element : Element) -> Element?
{
if let index = firstIndex(of: element) {
return remove(at: index)
}
return nil
}
}
Like remove(at: it returns the removed item or nil if the array doesn't contain the item.
If there are multiple occurrences of the same object use filter. However in cases like data source arrays where an index is associated with a particular object firstIndex(of is preferable because it's faster than filter.
Update:
In Swift 4.2+ you can remove one or multiple occurrences of beta with removeAll(where:):
array.removeAll{$0 == "beta"}
var a = ["one", "two", "three", "four", "five"]
// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }
For Swift 3, you can use index(where:) and include a closure that does the comparison of an object in the array ($0) with whatever you are looking for.
var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
array.remove(at: index)
}
Another nice and useful solution is to create this kind of extension:
extension Array where Element: Equatable {
#discardableResult mutating func remove(object: Element) -> Bool {
if let index = index(of: object) {
self.remove(at: index)
return true
}
return false
}
#discardableResult mutating func remove(where predicate: (Array.Iterator.Element) -> Bool) -> Bool {
if let index = self.index(where: { (element) -> Bool in
return predicate(element)
}) {
self.remove(at: index)
return true
}
return false
}
}
In this way, if you have your array with custom objects:
let obj1 = MyObject(id: 1)
let obj2 = MyObject(id: 2)
var array: [MyObject] = [obj1, obj2]
array.remove(where: { (obj) -> Bool in
return obj.id == 1
})
// OR
array.remove(object: obj2)
In Swift 5, Use this Extension:
extension Array where Element: Equatable{
mutating func remove (element: Element) {
if let i = self.firstIndex(of: element) {
self.remove(at: i)
}
}
}
example:
var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")
In Swift 3, Use this Extension:
extension Array where Element: Equatable{
mutating func remove (element: Element) {
if let i = self.index(of: element) {
self.remove(at: i)
}
}
}
example:
var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")
for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) is for loop in C-style and has been removed
Change your code to something like this to remove all similar object if it have looped:
let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
for index in indexes.reversed() {
arrContacts.remove(at: index)
}
The correct and working one-line solution for deleting a unique object (named "objectToRemove") from an array of these objects (named "array") in Swift 3 is:
if let index = array.enumerated().filter( { $0.element === objectToRemove }).map({ $0.offset }).first {
array.remove(at: index)
}
Swift 4
var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
if let index = students.firstIndex(where: { $0.hasPrefix("A") }) {
students.remove(at: index)
}
Swift Remove object from array
In Swift 3 and Swift 4
var array = ["a", "b", "c", "d", "e", "f"]
for (index, element) in array.enumerated().reversed() {
array.remove(at: index)
}
From Swift 4.2 you can use more advanced approach(faster and memory efficient)
array.removeAll(where: { $0 == "c" })
instead of
array = array.filter { !$0.hasPrefix("c") }
Read more here
Try this in Swift 3
array.remove(at: Index)
Instead of
array.removeAtIndex(index)
Update
"Declaration is only valid at file scope".
Make sure the object is in scope. You can give scope "internal", which is default.
index(of:<Object>) to work, class should conform to Equatable
This is official answer to find index of specific object, then you can easily remove any object using that index :
var students = ["Ben", "Ivy", "Jordell", "Maxime"]
if let i = students.firstIndex(of: "Maxime") {
// students[i] = "Max"
students.remove(at: i)
}
print(students)
// Prints ["Ben", "Ivy", "Jordell"]
Here is the link: https://developer.apple.com/documentation/swift/array/2994720-firstindex
Extension for array to do it easily and allow chaining for Swift 4.2 and up:
public extension Array where Element: Equatable {
#discardableResult
public mutating func remove(_ item: Element) -> Array {
if let index = firstIndex(where: { item == $0 }) {
remove(at: index)
}
return self
}
#discardableResult
public mutating func removeAll(_ item: Element) -> Array {
removeAll(where: { item == $0 })
return self
}
}
This is what I've used (Swift 5)...
extension Array where Element:Equatable
{
#discardableResult
mutating func removeFirst(_ item:Any ) -> Any? {
for index in 0..<self.count {
if(item as? Element == self[index]) {
return self.remove(at: index)
}
}
return nil
}
#discardableResult
mutating func removeLast(_ item:Any ) -> Any? {
var index = self.count-1
while index >= 0 {
if(item as? Element == self[index]) {
return self.remove(at: index)
}
index -= 1
}
return nil
}
}
var arrContacts:[String] = ["A","B","D","C","B","D"]
var contacts: [Any] = ["B","D"]
print(arrContacts)
var index = 1
arrContacts.removeFirst(contacts[index])
print(arrContacts)
index = 0
arrContacts.removeLast(contacts[index])
print(arrContacts)
Results:
["A", "B", "D", "C", "B", "D"]
["A", "B", "C", "B", "D"]
["A", "B", "C", "D"]
Important: The array from which you remove items must contain Equatable elements (such as objects, strings, number, etc.)
extension Array where Element: _ArrayType, Element.Generator.Element: Any {
func transpose() -> [Element] {
if self.isEmpty { return [Element]() }
let count = self[0].count
var out = [Element](repeating: Element(), count: count)
for outer in self {
for (index, inner) in outer.enumerated() {
out[index].append(inner)
}
}
return out
}
}
I am getting this error in Swift 3.0 after converting it from Swift 2.2. The elements of the array are also array. So how to define it in Swift 3.0?
extension Array where Element : Collection, Element.Index == Int, Element.IndexDistance == Int {
func transpose() -> [[Element.Iterator.Element]] {
typealias InnerElement = Element.Iterator.Element
if self.isEmpty { return [] }
let count = self[0].count
var out = [[InnerElement]](repeating: [InnerElement](), count: count)
for outer in self {
for (index, inner) in outer.enumerated() {
out[index].append(inner)
}
}
return out
}
}
I'm new to Swift and iOS programming.
I'm trying to test out a simple algorithm and need an array of Stacks. Don't have to be anything fancy (Stacks of Ints will do).
I got the Stack implementation from The Swift Programming Language documentation:
struct IntStack {
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
mutating func count() -> Int {
return items.count
}
mutating func show() {
println(items)
}
}
The count and show functions are my contribution. But when I try to declare an array of Stacks I get an error...
var lines = IntStack()[5]
"IntStack" does not have a member named subscript
I'm guessing it has something to do with Optionals but can figure out what it is.
Any help?
Details
Swift 5.1, Xcode 11.3.1
Generic Stack Implementation
Stackable protocol
protocol Stackable {
associatedtype Element
func peek() -> Element?
mutating func push(_ element: Element)
#discardableResult mutating func pop() -> Element?
}
extension Stackable {
var isEmpty: Bool { peek() == nil }
}
Stack
struct Stack<Element>: Stackable where Element: Equatable {
private var storage = [Element]()
func peek() -> Element? { storage.last }
mutating func push(_ element: Element) { storage.append(element) }
mutating func pop() -> Element? { storage.popLast() }
}
extension Stack: Equatable {
static func == (lhs: Stack<Element>, rhs: Stack<Element>) -> Bool { lhs.storage == rhs.storage }
}
extension Stack: CustomStringConvertible {
var description: String { "\(storage)" }
}
extension Stack: ExpressibleByArrayLiteral {
init(arrayLiteral elements: Self.Element...) { storage = elements }
}
Usage
var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.peek())
print(stack.pop())
print(stack)
print(stack == Stack<Int>())
stack = [3,2,1]
print(stack)
There's no problem with what you're doing there - that's just not the syntax for declaring an array. If you want an array of 5 stacks, you can do this:
[IntStack(), IntStack(), IntStack(), IntStack(), IntStack()]
Or, you can initialise the array like this:
Array(count: 5, repeatedValue: IntStack())
Also, you don't need to mark your functions as mutating unless they actually mutate the structure - so count() and show() don't need it.
It's possible to just extend arrays with stack specific methods. This might or might not be what you want, depending on if you want to disallow array like access.
protocol Stack {
associatedtype Element
mutating func push(item: Element)
// allows discarding the result without generating a warning.
#discardableResult
mutating func pop() -> Element?
func peek() -> Element?
var count: Int { get }
}
extension Array: Stack {
mutating func push(item: Element) {
self.append(item)
}
mutating func pop() -> Element? {
if let last = self.last {
self.remove(at: self.count - 1)
return last
}
return .none
}
func peek() -> Element? {
self.last
}
}
Simple test case:
class StackTests: XCTestCase {
func testExample() throws {
var stack = Array<Int>()
XCTAssertEqual(stack.peek(), .none, "stack is empty, peek returns none")
XCTAssertEqual(stack.pop(), .none, "stack is empty, pop returns none")
stack.push(item: 0)
stack.push(item: 1)
stack.push(item: 2)
XCTAssertEqual(stack.peek(), 2)
XCTAssertEqual(stack.pop(), 2)
XCTAssertEqual(stack.peek(), 1)
XCTAssertEqual(stack.pop(), 1)
XCTAssertEqual(stack.peek(), 0)
XCTAssertEqual(stack.pop(), 0)
}
}
There is no need to declare the size of the stack when you init it. Jus calling this should be enough.
var lines = IntStack()
Also note that your count() and show() methods should not be mutating since they don't modify the struct in any way.
Just look into this code. Stack example with generic data type and without using the array.
class Node<T>: CustomStringConvertible {
let value: T
var next: Node?
var description: String {
guard let next = next else { return "\(value)" }
return "\(value)\n" + String(describing: next)
}
init(value: T) {
self.value = value
}
}
// Stack class to hold all items
class Stack<T>: CustomStringConvertible {
var top: Node<T>?
var description: String {
guard let top = top else { return "---- Stack is EMPTY ----" }
return "---- Stack Begin ----\n" + String(describing: top) + "\n---- Stack End ----"
}
// push
func push(_ value: T) {
let currentTop = top
top = Node(value: value)
top?.next = currentTop
}
#discardableResult
func pop() -> T? {
let currentTop = top
top = top?.next
return currentTop?.value
}
#discardableResult
func peek() -> T? {
return top?.value
}
}
Excellent implementation! One thought: I think it should be:
func peek() -> Element? { storage.last }
Here is a Stack implementation using Swift Generics,
struct Fruit {
let fruitName : String
let color : String
init(_ name: String,_ color: String) {
self.fruitName = name
self.color = color
}
}
let fruit1 = Fruit("Apple", "Red")
let fruit2 = Fruit("Grapes", "Green")
let fruitStack = Stack<Fruit>()
fruitStack.push(fruit1)
fruitStack.push(fruit2)
let fruitFfromStack = fruitStack.pop()
print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack?.fruitName)) ,Color : \(String(describing: fruitFfromStack?.color))")
let fruitFfromStack1 = fruitStack.pop()
print("Fruit popped from Stack, Name : \(String(describing: fruitFfromStack1?.fruitName)) ,Color : \(String(describing: fruitFfromStack1?.color))")
Full code is here :
https://reactcodes.blogspot.com/2019/01/generic-stack-implementation-with.html
What I want to implement:
class func getSomeObject() -> [SomeObject]? {
let objects = Realm().objects(SomeObject)
return objects.count > 0 ? objects : nil
}
How can I return object as [SomeObject] instead if Results?
Weird, the answer is very straightforward. Here is how I do it:
let array = Array(results) // la fin
If you absolutely must convert your Results to Array, keep in mind there's a performance and memory overhead, since Results is lazy. But you can do it in one line, as results.map { $0 } in swift 2.0 (or map(results) { $0 } in 1.2).
I found a solution. Created extension on Results.
extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}
return array
}
}
and using like
class func getSomeObject() -> [SomeObject]? {
let objects = Realm().objects(SomeObject).toArray(SomeObject) as [SomeObject]
return objects.count > 0 ? objects : nil
}
With Swift 4.2 it's as simple as an extension:
extension Results {
func toArray() -> [Element] {
return compactMap {
$0
}
}
}
All the needed generics information is already a part of Results which we extend.
To use this:
let someModelResults: Results<SomeModel> = realm.objects(SomeModel.self)
let someModelArray: [SomeModel] = someModelResults.toArray()
This an another way of converting Results into Array with an extension with Swift 3 in a single line.
extension Results {
func toArray() -> [T] {
return self.map { $0 }
}
}
For Swift 4 and Xcode 9.2
extension Results {
func toArray<T>(type: T.Type) -> [T] {
return flatMap { $0 as? T }
}
}
With Xcode 10 flatMap is deprecated you can use compactMap for mapping.
extension Results {
func toArray<T>(type: T.Type) -> [T] {
return compactMap { $0 as? T }
}
}
Swift 3
extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
var array = [T]()
for i in 0 ..< count {
if let result = self[i] as? T {
array.append(result)
}
}
return array
}
}
Usage
class func getSomeObject() -> [SomeObject]? {
let defaultRealm = try! Realm()
let objects = defaultRealm.objects(SomeObject.self).toArray(ofType : SomeObject.self) as [SomeObject]
return objects.count > 0 ? objects : nil
}
Alternative : Using generics
class func getSomeObject() -> [T]? {
let objects = Realm().objects(T.self as! Object.Type).toArray(ofType : T.self) as [T]
return objects.count > 0 ? objects : nil
}
it's not a good idea to convert Results to Array, because Results is lazy. But if you need try this:
func toArray<T>(ofType: T.Type) -> [T] {
return flatMap { $0 as? T }
}
but better way is to pass Results wherever you need. Also you can convert Results to List instead of Array.
List(realm.objects(class))
if the first func is not working you can try this one:
var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Solution for Swift 4, Realm 3
extension Results {
func toArray<T>(ofType: T.Type) -> [T] {
let array = Array(self) as! [T]
return array
}
}
Now converting can be done as below
let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)
I'm not sure, if there is any efficient way to do this.
But you can do it by create a Swift array and append it in the loop.
class func getSomeObject() -> [SomeObject]? {
var someObjects: [SomeObject] = []
let objects = Realm().objects(SomeObject)
for object in objects{
someObjects += [object]
}
return objects.count > 0 ? someObjects : nil
}
If you feel it's too slow. I recommend you to pass around Realm Results object directly.
extension Results {
var array: [Element]? {
return self.count > 0 ? self.map { $0 } : nil
}
}
So, you can use like:
Realm().objects(SomeClass.self).filter("someKey ENDSWITH %#", "sth").array
extension Results {
func materialize() -> [Element] {
return Array(self)
}
}
Using Swift 5 and RealmSwift v10.20.0
This methods works:
private func convertToArray<R>(results: Results<R>) -> [R] where R: Object {
var arrayOfResults: [R] = []
for result in results {
arrayOfResults.append(result)
}
return arrayOfResults
}
I'm trying to add an extension method in Array like so:
extension Array {
func contains(obj: T) -> Bool {
let filtered = self.filter {$0 == obj}
return filtered.count > 0
}
}
But self.filter {$0 == obj} don't work. Compiler error:
could not find an overload for '==' that accepts the supplied arguments
you don't actually need to write an extension, you can use the global func contains from the Swift library:
contains([1,2,3], 1)
Swift 1.x
As I mentioned in the comments, there is a contains function. But to answer the question of how to write an extension and what the compiler error means:
The elements in the array can't necessarily be compared with ==. You need to make sure the parameter is Equatable and you need to make sure the array element is of the same type.
extension Array {
func contains<T : Equatable>(obj: T) -> Bool {
let filtered = self.filter {$0 as? T == obj}
return filtered.count > 0
}
}
Swift 2/Xcode 7 (Beta)
Swift 2 includes SequenceType.contains, which is exactly what you were trying to create.
This is made possible by a Swift syntax that allows restricting methods to certain (e.g. Equatable) type arguments. It looks like this:
extension SequenceType where Generator.Element: Equatable {
func contains(element: Self.Generator.Element) -> Bool {
...
}
}
I found that the built-in contains doesn't work with reference types. I needed this and solved it with the code below. I'm pasting it here because somebody else might be confused about contains() like I was.
extension Array {
func containsReference(obj: AnyObject) -> Bool {
for ownedItem in self {
if let ownedObject: AnyObject = ownedItem as? AnyObject {
if (ownedObject === obj) {
return true
}
}
}
return false
}
}
This works with Swift 2.1 for reference types pretty good.
extension SequenceType where Generator.Element: AnyObject {
func contains(obj: Self.Generator.Element?) -> Bool {
if obj != nil {
for item in self {
if item === obj {
return true
}
}
}
return false
}
}
For value types you can add this:
extension SequenceType where Generator.Element: Equatable {
func contains(val: Self.Generator.Element?) -> Bool {
if val != nil {
for item in self {
if item == val {
return true
}
}
}
return false
}
}
Not perfect, but this version built on nschum's answer supports optional arguments (though not arrays with optional types) as well:
extension Array {
private func typeIsOptional() -> Bool {
return reflect(self[0]).disposition == .Optional
}
func contains<U : Equatable>(obj: U) -> Bool {
if isEmpty {
return false
}
if (typeIsOptional()) {
NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
}
// cast type of array to type of argument to make it equatable
for item in self.map({ $0 as? U }) {
if item == obj {
return true
}
}
return false
}
// without this version, contains("foo" as String?) won't compile
func contains<U : Equatable>(obj: U?) -> Bool {
if isEmpty {
return false
}
if (typeIsOptional()) {
NSException(name:"Not supported", reason: "Optional Array types not supported", userInfo: nil).raise()
}
return obj != nil && contains(obj!)
}
}
If you have an array of optionals, you can get a copy of it with non-optionals (nil arguments removed) with this global function thanks to jtbandes:
func unwrapOptionals<T>(a: [T?]) -> [T] {
return a.filter { $0 != nil }.map { $0! }
}
Usage:
1> func unwrapOptionals<T>(a: [T?]) -> [T] {
2. return a.filter { $0 != nil }.map { $0! }
3. }
4>
5> let foo = ["foo" as String?]
foo: [String?] = 1 value {
[0] = "foo"
}
6> let bar = unwrapOptionals(foo)
bar: [String] = 1 value {
[0] = "foo"
}
For good measure, add one that just returns the array if its type is not optional. This way you avoid runtime errors if you call unwrapOptionals() on a non-optional array:
func unwrapOptionals<T>(a: [T]) -> [T] {
return a
}
Note you might think you could just call unwrapOptionals inside func contains<U : Equatable>(obj: U?). However, that doesn't work, because the Element type in the Array extension is just a type--it doesn't "know" it's an optional type. So if you call unwrapOptionals, the second version will be invoked, and you'll just get the array full of optionals back.