Is there a Swift one-liner to remove an element from an array if present and append it if not?
Asked Answered
G

3

5

This is a construct I come across quite a lot. Is there a nice way to one-line it in Swift?

I could just write an extension on Sequence for it, but I feel like there's a "obvious" higher-order-function / set theory technique that is eluding me.

if array.contains(element) {
    array.removeObject(object: element)
}
else {
    array.append(element)
}

I don't think the solution will even necessarily be nicer per se, it's just something I think about every time I have to write this.

Glochidiate answered 10/9, 2019 at 11:19 Comment(13)
Is there an option to use Set instead?Athena
the simple answer is not using an Array , try to use Set . Set doesn't accept duplicates so it won't be added if already exist.Jerz
@PGDev, let's say yes. I think I could colour in a Venn diagram of what I want, but I couldn't figure out how to code it using the options available in Swift's Set.Glochidiate
@SafoineMoncefAmine, that's not quite what that code is doing. It's swapping the presence of the element in the array.. Removing it if it's present and adding it if not.Glochidiate
The same in one line: array.contains(element) ? array.removeObject(object: element) : array.append(element)Handbarrow
@Starsky, my colleague suggested that. She suffixed it with //Technically one line 😂Glochidiate
@Handbarrow hahaha i was just answering that. Guess I should not anymore.Yocum
if array.contains(element) { array.removeObject(object: element) } else { array.append(element) }Amido
Rather than writing the shortest code try to write the most efficient code 😉 And there is no equivalent to NSArray's removeObject in Swift.Mothball
@vadian, rather than writing the "most efficient" code, profile your code occasionally and decide which bits are worth optimising. "Premature optimisation is the route of all evil" after all.Glochidiate
@vadian: https://mcmap.net/q/1923072/-objective-c-nsmutablearray-work-with-nilGlochidiate
@JamesWebster I generally agree, but there's obvious stuff that you should avoid in almost any case. Your proposed "append if doesn't exist" API would be O(n), and undoubtedly called as part of some loop that's at least O(n). O(n^2) explodes pretty fast, at very common real life data sets. People have thousands of songs, contacts, 10s/100s of thousands of files, etc.Backwash
@JamesWebster I know this looks funny and easy, but you actually asked for a one-liner ))))Handbarrow
G
10

I've found the part of Set Theory that was eluding me! The result I want is the Symmetric Difference of the two arrays and this is included in Swift's set:

var element = Set([1])
var set = Set([1, 2, 3])

set = set.symmetricDifference(element) //2, 3
set = set.symmetricDifference(element) //1, 2, 3
Glochidiate answered 10/9, 2019 at 11:36 Comment(2)
You don't need to convert the element to a set, you can just write set = set.symmetricDifference([1])Rufina
formSymmetricDifferenceAskew
A
2

You can try using Set instead,

var set: Set<Int> = [1, 2, 4]
if !set.insert(4).inserted {
    set.remove(4)
}
Athena answered 10/9, 2019 at 11:32 Comment(0)
M
1

Based on the great answer by. James Webster. We can enhance for reusability.

extension Set {
    /// Inserts given element if it doesn't exist in the set or removes it.
    ///
    mutating func withSymmetricDifference(_ element: Element) {
        self = symmetricDifference([element])
    }
}

Usage

var set = Set([1, 2, 3])
set.withSymmetricDifference(1) // [1, 2, 3]
set.withSymmetricDifference(1) // [2, 3]
Mesdames answered 27/8, 2022 at 17:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.