Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift array and dictionary performance, removeAll() vs new instance

Tags:

ios

swift

I have an array (or dictionary) and need to clear it. Performance wise, is it better to removeAll() or create a new instance?

var things = [Thing]()

// Need to clear things
things.removeAll()
// or
things = [Thing]()
like image 670
Steve Kuo Avatar asked Dec 06 '15 00:12

Steve Kuo


People also ask

Which one is faster array or set in Swift?

Array is faster than set in terms of initialization. Set is slower than an array in terms of initialization because it uses a hash process. The array allows to store duplicate elements in it. Set doesn't allow to store duplicate elements in it.

What is the difference between dictionary and array in Swift?

Swift provides three primary collection types, known as arrays, sets, and dictionaries, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.

Is Swift dictionary ordered?

There is no order. Dictionaries in Swift are an unordered collection type. The order in which the values will be returned cannot be determined.


1 Answers

(I accidentally misread your question and looked it up for Dictionary, see below for Array)

Dictionary

thing = [String : Thing]() vs. thing.removeAll()

Now that Swift is open-source, we can have a look at whether those two statements actually do something different.

New initialisation

After digging through the source I found the initialiser for a Dictionary here:

public init() {
  self = Dictionary<Key, Value>(minimumCapacity: 0)
}

/// Create a dictionary with at least the given number of
/// elements worth of storage.  The actual capacity will be the
/// smallest power of 2 that's >= `minimumCapacity`.
public init(minimumCapacity: Int) {
  _variantStorage =
    .Native(_NativeStorage.Owner(minimumCapacity: minimumCapacity))
}

As you can see, the underlying storage, which is the only property, gets assigned on initialisation.

removeAll

Now let's have a look at removeAll() from here:

  internal mutating func removeAll(keepCapacity keepCapacity: Bool) {
    if count == 0 {
      return
    }

    if !keepCapacity {
      self = .Native(NativeStorage.Owner(minimumCapacity: 2))
      return
    }

    if _fastPath(guaranteedNative) {
      nativeRemoveAll()
      return
    }

    switch self {
    case .Native:
      nativeRemoveAll()
    case .Cocoa(let cocoaStorage):
#if _runtime(_ObjC)
      self = .Native(NativeStorage.Owner(minimumCapacity: cocoaStorage.count))
#else
      _sanityCheckFailure("internal error: unexpected cocoa ${Self}")
#endif
    }
  }

Here you can see that the condition !keepCapacity will be true, because removeAll() is just removeAll(keepCapacity:) with a default argument of false. This code is from the storage enum, so it replaces itself with a new empty storage with a minimum capacity of 2.

Conclusion

Both statements do pretty much the same in theory, but I can imagine that in practice the initialisation can get optimised away, so that they do exactly the same.

Array

things = [Thing]() vs things.removeAll()

New initialisation

For array it's even easier to see here:

public init() {
  _buffer = _Buffer()
}

removeAll

See here:

public mutating func removeAll(keepCapacity keepCapacity: Bool = false) {
  if !keepCapacity {
    _buffer = _Buffer()
  }
  else {
    self.replaceRange(self.indices, with: EmptyCollection())
  }
}

As with the dictionary, _buffer is the only property of Array.

Conclusion

Same as for Dictionary: Both statements do pretty much the same in theory, but I can imagine that in practice the initialisation can get optimised away, so that they do exactly the same.

like image 99
Kametrixom Avatar answered Oct 03 '22 12:10

Kametrixom