78

I want to remove all elements of value x from an array that contains x, y and z elements

let arr = ['a', 'b', 'c', 'b']

How can I remove all elements of value 'b' from arr?

8 Answers 8

157

A filter:

 let farray = arr.filter {$0 != "b"} 
Sign up to request clarification or add additional context in comments.

6 Comments

You don't even need the braces as it's a trailing closure :) arr = arr.filter {$0 != 'b'} <3 swift
Just pointing out with regard to the above comment, without braces the compiler does throw 'Anonymous closure argument not contained in a closure'
she/he meant parentheses, not braces
with swift two, you can't use ', you would need to use " . so the answer will be let something = arr.filter{$0 != "b"}
I can't decide if even this one-liner is very legible or not.
|
26

If you need to modify initial array, you can use the function removeAll(where:) that is available in Swift 4.2/Xcode 10:

var arr = ["a", "b", "c", "b"]
arr.removeAll(where: { $0 == "b" })
print(arr) // output is ["a", "c"]

However, if you are using Xcode 9 you can find this function in Xcode9to10Preparation (this library provides implementations of some new functions from Xcode 10).

1 Comment

This works as long as the type is Equatable, like strings (as in the original question). Unlike every other modern language in the world, Swift does not offer a method to this does with regular values.
20
var array : [String]
array = ["one","two","one"]

let itemToRemove = "one"

while array.contains(itemToRemove) {
    if let itemToRemoveIndex = array.index(of: itemToRemove) {
        array.remove(at: itemToRemoveIndex)
    }
}

print(array)

Works on Swift 3.0.

7 Comments

Although this code is a little sloppy, it's about 45% faster than the filter solution
@AaronBrager I just made tests and it was 10% slower than filter. I guess comparing like that doesn't make much sense anyway since the results highly depend on how frequent and how evenly distributed are the items to remove in the source array.
@EricD. Yeah I agree it depends on the source array (I used the one in the question.) Here's my test - filter was never faster gist.github.com/getaaron/11b751b15489b0b95e9e
I think will depend on how much you care if the value you are trying to remove it isn't there and if you want to do something if the value doesn't exist on the array
No neet to use contains and index(of:). It would be much faster to use just index(of) since it returns an optional.
|
8

EDITED according to comments:

I like this approach:

var arr = ["a", "b", "c", "b"]

while let idx = arr.index(of:"b") {
    arr.remove(at: idx)
}

Original answer (before editing):

let arr = ['a', 'b', 'c', 'b']

if let idx = arr.index(of:"b") {
    arr.remove(at: idx)
}

5 Comments

Note that this will remove only the first array element equal to 'b'. To remove all of them (as required in this question), replace if by while.
Note that arr is declared as a constant you can't use a mutating method on it
Btw the single quote syntax used in the array declaration is wrong.
Martin and Leo are both right. Thx for pointing out. I have edited the answer. I must have never tried it because the constant declaration should not even compile. My bad.
This approach requires the type in Array<type> to be Equatable.
3

In Swift 3 I simply do:

arr = arr.filter { $0 != "a" } 

.filter, .sort and .map are great for saving time and solve lots of problems with little code.

This article has good examples and explain the differences and how they work: https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/

Comments

2

If you have more than one element to remove, thanks to first answer.

 var mainArray = ["a", "b", "qw", "qe"]
 let thingsToRemoveArray = ["qw", "b"] 


        for k in thingsToRemoveArray {
            mainArray =  mainArray.filter {$0 != k}
          }

Comments

1

A general approach is to exploit first class procedures. (However, this approach is much more powerful than what is required for your question.) To illustrate, say you want to avoid "Justin" repeatedly in many collections.

let avoidJustin = notEqualTester ("Justin")

let arrayOfUsers = // ...

arrayOfUsers.filter (avoidJustin)

let arrayOfFriends = // ...

arrayOfFriends.filter (avoidJustin)

With this, you avoid repeatedly creating a closure each time you want to avoid Justin. Here is notEqualTester which, given a that, returns a function of this that returns this != that.

func notEqualTester<T: Equatable> (that:T) -> ((this:T) -> Bool) {
  return { (this:T) -> Bool in return this != that }
}

The returned closure for this captures the value for that - which can be useful when that is no longer available.

Comments

0

If you only have one element of that value, this would probably be the easiest.

arr.remove(at: arr.index(of: ‘b’))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.