How to check if an element is in an array - arrays

In Swift, how can I check if an element exists in an array? Xcode does not have any suggestions for contain, include, or has, and a quick search through the book turned up nothing. Any idea how to check for this? I know that there is a method find that returns the index number, but is there a method that returns a boolean like ruby's #include??
Example of what I need:
var elements = [1,2,3,4,5]
if elements.contains(5) {
//do something
}

Swift 2, 3, 4, 5:
let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
print("yes")
}
contains() is a protocol extension method of SequenceType (for sequences of Equatable elements) and not a global method as in
earlier releases.
Remarks:
This contains() method requires that the sequence elements
adopt the Equatable protocol, compare e.g. Andrews's answer.
If the sequence elements are instances of a NSObject subclass
then you have to override isEqual:, see NSObject subclass in Swift: hash vs hashValue, isEqual vs ==.
There is another – more general – contains() method which does not require the elements to be equatable and takes a predicate as an
argument, see e.g. Shorthand to test if an object exists in an array for Swift?.
Swift older versions:
let elements = [1,2,3,4,5]
if contains(elements, 5) {
println("yes")
}

For those who came here looking for a find and remove an object from an array:
Swift 1
if let index = find(itemList, item) {
itemList.removeAtIndex(index)
}
Swift 2
if let index = itemList.indexOf(item) {
itemList.removeAtIndex(index)
}
Swift 3, 4
if let index = itemList.index(of: item) {
itemList.remove(at: index)
}
Swift 5.2
if let index = itemList.firstIndex(of: item) {
itemList.remove(at: index)
}

Updated for Swift 2+
Note that as of Swift 3 (or even 2), the extension below is no longer necessary as the global contains function has been made into a pair of extension method on Array, which allow you to do either of:
let a = [ 1, 2, 3, 4 ]
a.contains(2) // => true, only usable if Element : Equatable
a.contains { $0 < 1 } // => false
Historical Answer for Swift 1:
Use this extension: (updated to Swift 5.2)
extension Array {
func contains<T>(obj: T) -> Bool where T: Equatable {
return !self.filter({$0 as? T == obj}).isEmpty
}
}
Use as:
array.contains(1)

If you are checking if an instance of a custom class or struct is contained in an array, you'll need to implement the Equatable protocol before you can use .contains(myObject).
For example:
struct Cup: Equatable {
let filled:Bool
}
static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
return lhs.filled == rhs.filled
}
then you can do:
cupArray.contains(myCup)
Tip: The == override should be at the global level, not within your class/struct

I used filter.
let results = elements.filter { el in el == 5 }
if results.count > 0 {
// any matching items are in results
} else {
// not found
}
If you want, you can compress that to
if elements.filter({ el in el == 5 }).count > 0 {
}
Hope that helps.
Update for Swift 2
Hurray for default implementations!
if elements.contains(5) {
// any matching items are in results
} else {
// not found
}

(Swift 3)
Check if an element exists in an array (fulfilling some criteria), and if so, proceed working with the first such element
If the intent is:
To check whether an element exist in an array (/fulfils some boolean criteria, not necessarily equality testing),
And if so, proceed and work with the first such element,
Then an alternative to contains(_:) as blueprinted Sequence is to first(where:) of Sequence:
let elements = [1, 2, 3, 4, 5]
if let firstSuchElement = elements.first(where: { $0 == 4 }) {
print(firstSuchElement) // 4
// ...
}
In this contrived example, its usage might seem silly, but it's very useful if querying arrays of non-fundamental element types for existence of any elements fulfilling some condition. E.g.
struct Person {
let age: Int
let name: String
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
}
let persons = [Person(17, "Fred"), Person(16, "Susan"),
Person(19, "Hannah"), Person(18, "Sarah"),
Person(23, "Sam"), Person(18, "Jane")]
if let eligableDriver = persons.first(where: { $0.age >= 18 }) {
print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
// ...
} // Hannah can possibly drive the rental car in Sweden.
let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { $0.age == daniel.age }) {
print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
// ...
} // Sarah is the same age as Daniel.
Any chained operations using .filter { ... some condition }.first can favourably be replaced with first(where:). The latter shows intent better, and have performance advantages over possible non-lazy appliances of .filter, as these will pass the full array prior to extracting the (possible) first element passing the filter.
Check if an element exists in an array (fulfilling some criteria), and if so, remove the first such element
A comment below queries:
How can I remove the firstSuchElement from the array?
A similar use case to the one above is to remove the first element that fulfils a given predicate. To do so, the index(where:) method of Collection (which is readily available to array collection) may be used to find the index of the first element fulfilling the predicate, whereafter the index can be used with the remove(at:) method of Array to (possible; given that it exists) remove that element.
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let indexOfFirstSuchElement = elements.index(where: { $0 == "c" }) {
elements.remove(at: indexOfFirstSuchElement)
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}
Or, if you'd like to remove the element from the array and work with, apply Optional:s map(_:) method to conditionally (for .some(...) return from index(where:)) use the result from index(where:) to remove and capture the removed element from the array (within an optional binding clause).
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let firstSuchElement = elements.index(where: { $0 == "c" })
.map({ elements.remove(at: $0) }) {
// if we enter here, the first such element have now been
// remove from the array
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
// and we may work with it
print(firstSuchElement) // c
}
Note that in the contrived example above the array members are simple value types (String instances), so using a predicate to find a given member is somewhat over-kill, as we might simply test for equality using the simpler index(of:) method as shown in #DogCoffee's answer. If applying the find-and-remove approach above to the Person example, however, using index(where:) with a predicate is appropriate (since we no longer test for equality but for fulfilling a supplied predicate).

An array that contains a property that equals to
yourArray.contains(where: {$0.propertyToCheck == value })
Returns boolean.

The simplest way to accomplish this is to use filter on the array.
let result = elements.filter { $0==5 }
result will have the found element if it exists and will be empty if the element does not exist. So simply checking if result is empty will tell you whether the element exists in the array. I would use the following:
if result.isEmpty {
// element does not exist in array
} else {
// element exists
}

Swift 4/5
Another way to achieve this is with the filter function
var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
print("found")
} else {
print("not found")
}

As of Swift 2.1 NSArrays have containsObjectthat can be used like so:
if myArray.containsObject(objectImCheckingFor){
//myArray has the objectImCheckingFor
}

Array
let elements = [1, 2, 3, 4, 5, 5]
Check elements presence
elements.contains(5) // true
Get elements index
elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil
Get element count
let results = elements.filter { element in element == 5 }
results.count // 2

Just in case anybody is trying to find if an indexPath is among the selected ones (like in a UICollectionView or UITableView cellForItemAtIndexPath functions):
var isSelectedItem = false
if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
if contains(selectedIndexPaths, indexPath) {
isSelectedItem = true
}
}

if user find particular array elements then use below code same as integer value.
var arrelemnts = ["sachin", "test", "test1", "test3"]
if arrelemnts.contains("test"){
print("found") }else{
print("not found") }

Here is my little extension I just wrote to check if my delegate array contains a delegate object or not (Swift 2). :) It Also works with value types like a charm.
extension Array
{
func containsObject(object: Any) -> Bool
{
if let anObject: AnyObject = object as? AnyObject
{
for obj in self
{
if let anObj: AnyObject = obj as? AnyObject
{
if anObj === anObject { return true }
}
}
}
return false
}
}
If you have an idea how to optimize this code, than just let me know.

Swift
If you are not using object then you can user this code for contains.
let elements = [ 10, 20, 30, 40, 50]
if elements.contains(50) {
print("true")
}
If you are using NSObject Class in swift. This variables is according to my requirement. you can modify for your requirement.
var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!
This is for a same data type.
{ $0.user_id == cliectScreenSelectedObject.user_id }
If you want to AnyObject type.
{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }
Full condition
if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {
cliectScreenSelected.append(cliectScreenSelectedObject)
print("Object Added")
} else {
print("Object already exists")
}

what about using a hash table for the job, like this?
first, creating a "hash map" generic function, extending the Sequence protocol.
extension Sequence where Element: Hashable {
func hashMap() -> [Element: Int] {
var dict: [Element: Int] = [:]
for (i, value) in self.enumerated() {
dict[value] = i
}
return dict
}
}
This extension will work as long as the items in the array conform to Hashable, like integers or strings, here is the usage...
let numbers = Array(0...50)
let hashMappedNumbers = numbers.hashMap()
let numToDetect = 35
let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!
print(indexOfnumToDetect) // prints 35
But for now, let's just focus in check if the element is in the array.
let numExists = indexOfnumToDetect != nil // if the key does not exist
means the number is not contained in the collection.
print(numExists) // prints true

Swift 4.2 +
You can easily verify your instance is an array or not by the following function.
func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
if let _ = object as? [T] {
return true
}
return false
}
Even you can access it as follows. You will receive nil if the object wouldn't be an array.
func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
if let array = object as? [T] {
return array
}
return nil
}

You can add an extension for Array as such:
extension Array {
func contains<T>(_ object: T) -> Bool where T: Equatable {
!self.filter {$0 as? T == object }.isEmpty
}
}
This can be used as:
if myArray.contains(myItem) {
// code here
}

Related

How to change a value of struct that is in array?

I'm using swift for my project.
I have an array of structs named Instrument. Later on I made a function that returns specific Instrument from array. Then I wanted to change value on one of its property, but this change is not reflected inside the array.
I need to have this array to include all the changes on the elements inside. What do you think is the best practice here?
Change Instrument from struct to class.
Somehow rewrite the function that returns Instrument from array.
Right now I use this function:
func instrument(for identifier: String) -> Instrument? {
if let instrument = instruments.filter({ $0.identifier == identifier }).first {
return instrument
}
return nil
}
I start with the struct because swift is known to be language for structs and I want to learn when to use struct of class.
thanks
With an array of struct Instrument, you can obtain the index for the Instrument with a particular identifier, and use that to access and modify a property of the Instrument.
struct Instrument {
let identifier: String
var value: Int
}
var instruments = [
Instrument(identifier: "alpha", value: 3),
Instrument(identifier: "beta", value: 9),
]
if let index = instruments.index(where: { $0.identifier == "alpha" }) {
instruments[index].value *= 2
}
print(instruments) // [Instrument(identifier: "alpha", value: 6), Instrument(identifier: "beta", value: 9)]
If you stick to the value type approach (and given that the identifier is not unique: otherwise, consider using a dictionary for simple extract-and-replace logic), you could write a mutating function to the type which owns the [Instruments] array, which finds a (first) Instrument instance in the array and mutates it using a supplied closure. E.g. (thanks #Hamish for improvements!):
struct Instrument {
let identifier: String
var changeThis: Int
init(_ identifier: String, _ changeThis: Int) {
self.identifier = identifier
self.changeThis = changeThis
}
}
struct Foo {
var instruments: [Instrument]
#discardableResult // do not necessarily make use of the return result (no warning if not)
mutating func updateInstrument(forFirst identifier: String,
using mutate: (inout Instrument) -> ()) -> Bool {
if let idx = instruments.indices
.first(where: { instruments[$0].identifier == identifier }) {
// mutate this instrument (in-place) using supplied closure
mutate(&instruments[idx])
return true // replacement successful
}
return false // didn't find such an instrument
}
}
Example usage:
var foo = Foo(instruments:
[Instrument("a", 1), Instrument("b", 2),
Instrument("c", 3), Instrument("b", 4)])
// make use of result of call
if foo.updateInstrument(forFirst: "b", using: { $0.changeThis = 42 }) {
print("Successfully mutated an instrument")
} // Successfully mutated an instrument
// just attempt mutate and discard the result
foo.updateInstrument(forFirst: "c", using: { $0.changeThis = 99 })
print(foo.instruments)
/* [Instrument(identifier: "a", changeThis: 1),
Instrument(identifier: "b", changeThis: 42),
Instrument(identifier: "c", changeThis: 99),
Instrument(identifier: "b", changeThis: 4)] */
As shown in #Owen:s answer, an even neater approach to finding the first index for a certain predicate on the element is using the index(where:) method of array (rather than indices.first(where:) as used above). Using the index(where:) approach in the complete example above would simply correspond to replacing
if let idx = instruments.indices
.first(where: { instruments[$0].identifier == identifier }) { ...
with
if let idx = instruments
.index(where: { $0.identifier == identifier }) { ...
in the updateInstrument(forFirst:using) method of Foo.
We could further condense the updateInstrument(forFirst:using) method by applying the map function of Optional to perform the (possible) replacement and boolean return in a single line:
struct Foo {
var instruments: [Instrument]
#discardableResult
mutating func updateInstrument(forFirst identifier: String,
using mutate: (inout Instrument) -> ()) -> Bool {
return instruments
.index(where: { $0.identifier == identifier })
.map { mutate(&instruments[$0]) } != nil
}
}

Remove AnyObject from Swift dictionary

I have a dictionary:
var dict:[NSObject:[AnyObject]]
I want to remove an object from the dictionary by value.
func removeObject(anObject:AnyObject) {
for key in dict.keys {
dict[key] = dict[key]!.filter({$0 == anObject})
}
}
but I'm getting this error:
Binary operator '==' cannot be applied to two 'AnyObject' operands
What's the best way to remove this object? I want to keep it generic as possible.
If you are looking to remove object that are semantically equal to anObject, it and the elements in the array must conform to the Equatable protocol. Make a your function a generic one like this:
var dict = [NSObject:[AnyObject]]()
dict["key1"] = [1,2,3,"Hello world"]
dict["key2"] = [3,4,5]
func removeObject<T: Equatable>(anObject: T) {
for key in dict.keys {
dict[key] = dict[key]!.filter {
if let element = $0 as? T where element == anObject {
return false
} else {
return true
}
}
}
}
// Remove all number 3
removeObject(3)
print(dict)
Note that this can have some odd results:
dict["key1"] = [1, 2, 3]
dict["key2"] = [4, 3.4, 3.9]
removeObject(3.0) // 3.4 and 3.9 remain
removeObject(3) // 3.4 and 3.9 gone
That's because 3.4 and 3.9 become 3 when you cast them as Int

Swift array extension cannot append equitable item [duplicate]

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!)
}
}
}

How can I tell what the index of an item in a multidimensional array would be if the array were flattened?

I have a multidimensional array with some repeated elements in the deepest level:
[
["taco","burrito"],
["chalupa","taco","bread"]
["pizza","lasagna"],
["pizza","taco","burrito"]
["salad","sandwich"],
["meat","turkey"]
["cups","chicken"],
["rabbit","taco", "chicken", "salad"]
]
I have flattened this array into...
[
"taco",
"burrito",
"chalupa",
"taco",
"bread",
"pizza",
"lasagna",
etc...
]
I have found the second occurrence of the word "taco" in the multidimensional array and know its index.
How can I translate that index to an index in the flattened array?
So in this example it would be...
multiDimensionalArray[0][1][1]
=
flatArray[3]
Swift doesn't have native support for flattening arrays. You could roll this out yourself, or you could use ExSwift which has a flatten method. If you flatten the array successfully, obviously you could then determine which index the value is at using indexOfObject. Since you have multiple identical objects, you may want to use indexesOfObjectsPassingTest, which will give you an index set for all indexes matching the test you provide.
First of all you need a function to flatten the array into an array of strings in order to gain the true indices of the elements.
public func flattenArray(array: Array<AnyObject>) -> Array<String> {
var flattened: Array<String> = []
for object: AnyObject in array {
if object is Array<AnyObject> {
for string in flattenArray(object as Array<AnyObject>) {
flattened.append(string)
}
} else if object is String {
flattened.append(object as String)
}
}
return flattened
}
Then you need to write a function that will obtain the index of an element in an array at a certain number of occurrences
public func indexOfString(string: String, inArray array: Array<String>, occurance: Int = 1) -> Int? {
var occurancesSoFar = 0
var index: Int? = nil
var currentIndex = 0
for object in array {
if object == string {
if (++occurancesSoFar == occurance) {
index = currentIndex
}
}
++currentIndex
}
return index
}
Calling the above functions in order gives the correct index value:
let array = [
["taco","burrito"],
["chalupa","taco","bread"],
["pizza","lasagna"],
["pizza","taco","burrito"],
["salad","sandwich"],
["meat","turkey"],
["cups","chicken"],
["rabbit","taco", "chicken", "salad"]
]
let flat = flattenArray(array)
let index = indexOfString("taco", inArray: flat, occurance: 2)
println(index) // Optional(3)
Using these methods you could encapsulate them into a single function perhaps called
func flattenAndFindElement(element: String,
inArray array: Array<AnyObject>,
atOccurrence occurrence: Int) -> Int?
or something similar.
Hope that helps answer your question.
Here is what I ended up doing:
func findFlattenedIndex(array: Array<Array<String>>, firstIndex: Int, secondIndex: Int) -> Int {
var flatIndex = 0
for (index1,secondTier) in enumerate(array) {
for element in secondTier {
if index1 != firstIndex{
println(element)
flatIndex += 1
}
}
if index1 == firstIndex {
flatIndex += secondIndex
return flatIndex
break
}
}
return flatIndex
}
Of course this could be modified to deal with any number of dimensions.
Thanks for everyone's help with this.

How to remove an element from an array in Swift

How can I unset/remove an element from an array in Apple's new language Swift?
Here's some code:
let animals = ["cats", "dogs", "chimps", "moose"]
How could the element animals[2] be removed from the array?
The let keyword is for declaring constants that can't be changed. If you want to modify a variable you should use var instead, e.g:
var animals = ["cats", "dogs", "chimps", "moose"]
animals.remove(at: 2) //["cats", "dogs", "moose"]
A non-mutating alternative that will keep the original collection unchanged is to use filter to create a new collection without the elements you want removed, e.g:
let pets = animals.filter { $0 != "chimps" }
Given
var animals = ["cats", "dogs", "chimps", "moose"]
Remove first element
animals.removeFirst() // "cats"
print(animals) // ["dogs", "chimps", "moose"]
Remove last element
animals.removeLast() // "moose"
print(animals) // ["cats", "dogs", "chimps"]
Remove element at index
animals.remove(at: 2) // "chimps"
print(animals) // ["cats", "dogs", "moose"]
Remove element of unknown index
For only one element
if let index = animals.firstIndex(of: "chimps") {
animals.remove(at: index)
}
print(animals) // ["cats", "dogs", "moose"]
For multiple elements
var animals = ["cats", "dogs", "chimps", "moose", "chimps"]
animals = animals.filter(){$0 != "chimps"}
print(animals) // ["cats", "dogs", "moose"]
Notes
The above methods modify the array in place (except for filter) and return the element that was removed.
Swift Guide to Map Filter Reduce
If you don't want to modify the original array, you can use dropFirst or dropLast to create a new array.
Updated to Swift 5.2
The above answers seem to presume that you know the index of the element that you want to delete.
Often you know the reference to the object you want to delete in the array. (You iterated through your array and have found it, e.g.) In such cases it might be easier to work directly with the object reference without also having to pass its index everywhere. Hence, I suggest this solution. It uses the identity operator !==, which you use to test whether two object references both refer to the same object instance.
func delete(element: String) {
list = list.filter { $0 != element }
}
Of course this doesn't just work for Strings.
Swift 5:
Here is a cool and easy extension to remove elements in an array, without filtering :
extension Array where Element: Equatable {
// Remove first collection element that is equal to the given `object`:
mutating func remove(object: Element) {
guard let index = firstIndex(of: object) else {return}
remove(at: index)
}
}
Usage :
var myArray = ["cat", "barbecue", "pancake", "frog"]
let objectToRemove = "cat"
myArray.remove(object: objectToRemove) // ["barbecue", "pancake", "frog"]
Also works with other types, such as Int since Element is a generic type:
var myArray = [4, 8, 17, 6, 2]
let objectToRemove = 17
myArray.remove(object: objectToRemove) // [4, 8, 6, 2]
For Swift4:
list = list.filter{$0 != "your Value"}
As of Xcode 10+, and according to the WWDC 2018 session 223, "Embracing Algorithms," a good method going forward will be mutating func removeAll(where predicate: (Element) throws -> Bool) rethrows
Apple's example:
var phrase = "The rain in Spain stays mainly in the plain."
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
phrase.removeAll(where: { vowels.contains($0) })
// phrase == "Th rn n Spn stys mnly n th pln."
see Apple's Documentation
So in the OP's example, removing animals[2], "chimps":
var animals = ["cats", "dogs", "chimps", "moose"]
animals.removeAll(where: { $0 == "chimps" } )
// or animals.removeAll { $0 == "chimps" }
This method may be preferred because it scales well (linear vs quadratic), is readable and clean. Keep in mind that it only works in Xcode 10+, and as of writing this is in Beta.
If you have array of custom Objects, you can search by specific property like this:
if let index = doctorsInArea.firstIndex(where: {$0.id == doctor.id}){
doctorsInArea.remove(at: index)
}
or if you want to search by name for example
if let index = doctorsInArea.firstIndex(where: {$0.name == doctor.name}){
doctorsInArea.remove(at: index)
}
You could do that. First make sure Dog really exists in the array, then remove it. Add the for statement if you believe Dog may happens more than once on your array.
var animals = ["Dog", "Cat", "Mouse", "Dog"]
let animalToRemove = "Dog"
for object in animals {
if object == animalToRemove {
animals.remove(at: animals.firstIndex(of: animalToRemove)!)
}
}
If you are sure Dog exits in the array and happened only once just do that:
animals.remove(at: animals.firstIndex(of: animalToRemove)!)
If you have both, strings and numbers
var array = [12, 23, "Dog", 78, 23]
let numberToRemove = 23
let animalToRemove = "Dog"
for object in array {
if object is Int {
// this will deal with integer. You can change to Float, Bool, etc...
if object == numberToRemove {
array.remove(at: array.firstIndex(of: numberToRemove)!)
}
}
if object is String {
// this will deal with strings
if object == animalToRemove {
array.remove(at: array.firstIndex(of: animalToRemove)!)
}
}
}
If you don't know the index of the element that you want to remove, and the element is conform the Equatable protocol, you can do:
animals.remove(at: animals.firstIndex(of: "dogs")!)
See Equatable protocol answer:How do I do indexOfObject or a proper containsObject
Few Operation relates to Array in Swift
Create Array
var stringArray = ["One", "Two", "Three", "Four"]
Add Object in Array
stringArray = stringArray + ["Five"]
Get Value from Index object
let x = stringArray[1]
Append Object
stringArray.append("At last position")
Insert Object at Index
stringArray.insert("Going", at: 1)
Remove Object
stringArray.remove(at: 3)
Concat Object value
var string = "Concate Two object of Array \(stringArray[1]) + \(stringArray[2])"
Remove elements using indexes array:
Array of Strings and indexes
let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
let indexAnimals = [0, 3, 4]
let arrayRemainingAnimals = animals
.enumerated()
.filter { !indexAnimals.contains($0.offset) }
.map { $0.element }
print(arrayRemainingAnimals)
//result - ["dogs", "chimps", "cow"]
Array of Integers and indexes
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let indexesToRemove = [3, 5, 8, 12]
numbers = numbers
.enumerated()
.filter { !indexesToRemove.contains($0.offset) }
.map { $0.element }
print(numbers)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Remove elements using element value of another array
Arrays of integers
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Arrays of strings
let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
let arrayRemoveLetters = ["a", "e", "g", "h"]
let arrayRemainingLetters = arrayLetters.filter {
!arrayRemoveLetters.contains($0)
}
print(arrayRemainingLetters)
//result - ["b", "c", "d", "f", "i"]
I came up with the following extension that takes care of removing elements from an Array, assuming the elements in the Array implement Equatable:
extension Array where Element: Equatable {
mutating func removeEqualItems(_ item: Element) {
self = self.filter { (currentItem: Element) -> Bool in
return currentItem != item
}
}
mutating func removeFirstEqualItem(_ item: Element) {
guard var currentItem = self.first else { return }
var index = 0
while currentItem != item {
index += 1
currentItem = self[index]
}
self.remove(at: index)
}
}
Usage:
var test1 = [1, 2, 1, 2]
test1.removeEqualItems(2) // [1, 1]
var test2 = [1, 2, 1, 2]
test2.removeFirstEqualItem(2) // [1, 1, 2]
Regarding #Suragch's Alternative to "Remove element of unknown index":
There is a more powerful version of "indexOf(element)" that will match on a predicate instead of the object itself. It goes by the same name but it called by myObjects.indexOf{$0.property = valueToMatch}. It returns the index of the first matching item found in myObjects array.
If the element is an object/struct, you may want to remove that element based on a value of one of its properties. Eg, you have a Car class having car.color property, and you want to remove the "red" car from your carsArray.
if let validIndex = (carsArray.indexOf{$0.color == UIColor.redColor()}) {
carsArray.removeAtIndex(validIndex)
}
Foreseeably, you could rework this to remove "all" red cars by embedding the above if statement within a repeat/while loop, and attaching an else block to set a flag to "break" out of the loop.
Swift 5
guard let index = orders.firstIndex(of: videoID) else { return }
orders.remove(at: index)
This should do it (not tested):
animals[2...3] = []
Edit: and you need to make it a var, not a let, otherwise it's an immutable constant.
extension to remove String object
extension Array {
mutating func delete(element: String) {
self = self.filter() { $0 as! String != element }
}
}
I use this extension, almost same as Varun's, but this one (below) is all-purpose:
extension Array where Element: Equatable {
mutating func delete(element: Iterator.Element) {
self = self.filter{$0 != element }
}
}
To remove elements from an array, use the remove(at:),
removeLast() and removeAll().
yourArray = [1,2,3,4]
Remove the value at 2 position
yourArray.remove(at: 2)
Remove the last value from array
yourArray.removeLast()
Removes all members from the set
yourArray.removeAll()

Resources