Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A Method for Removing All Elements in One Array that Exist in Another #166

Open
michaeleisel opened this issue Aug 27, 2021 · 5 comments
Open

Comments

@michaeleisel
Copy link

michaeleisel commented Aug 27, 2021

This is a "subtract" operation, e.g.:

let animals = ["Cow", "Bulldog", "Labrador"]
return animals.without(["Bulldog", "Labrador"]) // ["Cow"]

We can see that this is an operation Swift developers are already trying to do from SO questions (1, 2), and it exists in other languages like Ruby.

This is a proposal to get consensus on it. And if people like it, I'd be happy to implement it.

@mdznr
Copy link
Contributor

mdznr commented Sep 2, 2021

That example could be written quite easily with filter(_:) without the need for a separate without(_:) function:

let excludedAnimals = ["Bulldog", "Labrador"]
return animals.filter({ !excludedAnimals.contains($0) }) // ["Cow"]

The algorithmic complexity of this, however, is O(n×m) where n is the number of elements in the first array and m is the number of elements in the exclusion array. If converting the elements into a Set, you can get O(n) behavior, since contains(_:) on Set is effectively O(1).

let excludedAnimals = Set(arrayLiteral: "Bulldog", "Labrador")
return animals.filter({ !excludedAnimals.contains($0) }) // ["Cow"]

I wouldn’t expect there’d be a ton of value in a function like this specifically, unless it automatically managed the conditional conversion to a Set in cases where that overhead is expected to be less than the cost of an O(n) contains(_:) check.

@michaeleisel
Copy link
Author

It could be written that way, just as most things could be written via a reduce, but I think the popularity of this use case (based on those SO questions and my own experience) warrants a more convenient solution. We may also want to make this a lazy sequence, which wouldn't be so trivial for people to do on their own.

@LucianoPAlmeida
Copy link
Contributor

Conceptually this would be just a generalization of Set.subtract https://developer.apple.com/documentation/swift/set/2853597-subtract. I think this would be a convenient utility as a lazy sequence since it is not so trivial to implement by hand and its use is common enough IMO.

One suggestion, is that this issue tracking would not reach to many people because only few watch this repo, so maybe if we want an input from more members of the community an idea would be have a forums thread for it under algorithms topic, if you think is worth it. But it is only a suggestion :)

@lorentey
Copy link
Member

lorentey commented Sep 7, 2021

Quick style note:

let excludedAnimals = Set(arrayLiteral: "Bulldog", "Labrador")

This usually reads better when spelled:

let excludedAnimals: Set = ["Bulldog", "Labrador"]

@mdznr
Copy link
Contributor

mdznr commented Sep 7, 2021

@lorentey Good point—I had forgotten about that. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants