Swift adding to end of array - swift

I know that Array has the append(_:) method, but this mutates the original array.
Why doesn't Array also implement appending(_:) which would return a new array with that element appended? I've implemented this a few times now, but am wondering if there is a reason why it doesn't already exist?
(My only guess would be that this is to do with efficiency - if you used this method in a loop you would be copying your array multiple times?)

You can make an extension of Array do to this :
extension Array{
func appending(_ element:Element) -> Array<Element>{
var result = self
result.append(element)
return result
}
}

What are we discussing?
Starting from 'append' documentation:
/// Append `newElement` to the Array.
///
/// - Complexity: Amortized O(1) unless `self`'s storage is shared with another live array; O(`count`) if `self` does not wrap a bridged
NSArray; otherwise the efficiency is unspecified..
public mutating func append(newElement: Element)
You need to have knowledge about pointer and smart pointer.
M elements
var a = [1, 2, 3]
Is a simple array.
If you append N elements, complexity will be O(N)
func addElements() {
for elment in [4, 5, 6] {
a.append(element)
}
}
If you create a new array starting from a:
var b = a
At run time b points to a, so if you execute again addElements complexity will be O(M) in order to copy original array plus O(N) in order to add N elements.
Why documentation says?
"otherwise the efficiency is unspecified.."
Because in this example we have a simple array of integer, but the behaviour of copying array of custom objects is unpredictable.

Related

suffix array Index out of bounds

I have an array , when I suffix array and want to select element , I get error: Index out of bounds.
But when I prefix array and select element, It's sucess.
How should I do that I can select after suffix array?
Here is code:
let array = [1,2,3,4,5,6,7,8,9,10]
let suffixArray = array.suffix(5)//[6,7,8,9,10]
let prefixArray = array.prefix(5)//[1,2,3,4,5]
print(suffixArray[2])//Index out of bounds
print(prefixArray[2])//sucess print "3"
The problem you are having is that with .suffix the array does not start with 0. So if you wanted to print the 3rd number in the suffix array, you would have to call print(suffixArray[7].
If you read the description for the return value here. It reads:
A subsequence terminating at the end of the collection with at most maxLength elements.
And if you read the description to subsequence:
A collection representing a contiguous subrange of this collection’s elements. The subsequence shares indices with the original collection.
Full example for playground:
let array = [1,2,3,4,5,6,7,8,9,10]
let suffixArray = array.suffix(5) // [6,7,8,9,10]
let prefixArray = array.prefix(5) // [1,2,3,4,5]
var newSuffixArray: [Int] = []
for i in suffixArray {
newSuffixArray.append(i)
}
print(suffixArray[7]) // 8
print(newSuffixArray[2]) // 8
print(prefixArray[2]) // 3
Both prefix and suffix return an ArraySlice rather than another Array.
Here's an excerpt from the ArraySlice documentation:
Unlike Array and ContiguousArray, the starting index for an
ArraySlice instance isn’t always zero. Slices maintain the same
indices of the larger array for the same elements, so the starting
index of a slice depends on how it was created, letting you perform
index-based operations on either a full array or a slice. Sharing
indices between collections and their subsequences is an important
part of the design of Swift’s collection algorithms.
You can see that by looking into the indices property of prefixArray and suffixArray.
Generally you are encouraged to use methods of accessing elements that collections provide instead of assuming values of indices.

Is first(where:) Method always O(n) or it can be O(1) with usage of Set or Dictionary?

I like to know if I use Set instead of Array can my method of first(where:) became Complexity:O(1)?
Apple says that the first(where:) Method is O(n), is it in general so or it depends on how we use it?
for example look at these two ways of coding:
var numbers: [Int] = [Int]()
numbers = [3, 7, 4, -2, 9, -6, 10, 1]
if let searchResult = numbers.first(where: { value in value == -2 })
{
print("The number \(searchResult) Exist!")
}
else
{
print("The number does not Exist!")
}
and this:
var numbers: Set<Int> = Set<Int>()
numbers = [3, 7, 4, -2, 9, -6, 10, 1]
if let searchResult = numbers.first(where: { value in value == -2 })
{
print("The number \(searchResult) Exist!")
}
else
{
print("The number does not Exist!")
}
can we say that in second way Complexity is O(1)?
It's still O(n) even when you use a Set. .first(where:) is defined on a sequence, and it is necessary to check the items in the sequence one at a time to find the first one that makes the predicate true.
Your example is simply checking if the item exists in the Set, but since you are using .first(where:) and a predicate { value in value == -2} Swift will run that predicate for each element in the sequence in turn until it finds one that returns true. Swift doesn't know that you are really just checking to see if the item is in the set.
If you want O(1), then use .contains(-2) on the Set.
I recommend to learn more about Big-O notation. O(1) is a strict subset of O(n). Thus every function that is O(1) is also in O(n).
That said, Apple’s documentation is actually misleading as it does not take the complexity of the predicate function into account. The following is clearly O(n^2):
numbers.first(where: { value in numbers.contains(value + 42) })
Both Set and Dictionary conform to the Sequence protocol, which is the one that exposes the first(where:) function. And this function has the following requirement, taken from the documentation:
Complexity: O(n), where n is the length of the sequence.
Now, this is the upper limit of the function complexity, it might well be that some sequences optimize the search based on their data type and the storage details.
Bottom line: you need to reach the documentation for a particular type if you want to know more about the performance of some feature, however if you're only circulating some protocol references, then you should assume the "worst" - aka what's in the protocol documentation.
This is the implementation of the first(where:) function in the sequence:
/// - Complexity: O(*n*), where *n* is the length of the sequence.
#inlinable
public func first(
where predicate: (Element) throws -> Bool
) rethrows -> Element? {
for element in self {
if try predicate(element) {
return element
}
}
return nil
}
From the Swift Source Code on the Github
As you can see, It's a simple for loop and the complexity is O(n) (assuming the predicate complexity is 1 🤷🏻‍♂️).
The predicate executes n times. So the worst case is O(n)
The Set has not an overload for this function (since it is nonsense and there will be nothing more than the first one in a Set). If you know about the sequence and you are just looking for a value (not a predicate), just use contains or firstIndex(of:). These two have overloads with the complexity of O(1)
From the Swift Source Code on the Github

Does Swift copy on mutation in this scenario?

Essentially what I want is a temporary alias for a class property to improve readability.
I'm in the situation described by the following code and I can't see a straightforward solution. What I want to avoid is y being copied on mutation and then copied back.
Renaming y would reduce the readability of the actual algorithm a lot.
Is the Swift compiler smart enough to not actually allocate new memory and how would I be able to know that?
If not, how to prevent copying?
class myClass {
var propertyWithLongDescriptiveName: [Float]
func foo() {
var y = propertyWithLongDescriptiveName
// mutate y with formulas where y corresponds to a `y` from some paper
// ...
propertyWithLongDescriptiveName = y
}
// ...
}
struct Array is a value types in Swift, which means that they are always
copied when assigned to another variable. However, each struct Array
contains pointers (not visible in the public interface) to the actual
element storage. Therefore after
var a = [1, 2, 3, 4]
var b = a
both a and b are (formally independent) values, but with pointers to the same element storage.
Only when one of them is mutated, a copy of the element storage is made.
This is called "copy on write" and for example explained in
Friday Q&A 2015-04-17: Let's Build Swift.Array
So after
b[0] = 17
a and b are values with pointers to different (independent) element storage.
Further mutation of b does not copy the element storage again
(unless b is copied to another variable). Finally, if you assign
the value back
a = b
the old element storage of a is released, and both values are pointers to the same storage again.
Therefore in your example:
var y = propertyWithLongDescriptiveName
// ... mutate y ...
propertyWithLongDescriptiveName = y
a copy of the element storage is made exactly once (assuming
that you don't copy y to an additional variable).
If the array size does not change then a possible approach could be
var propertyWithLongDescriptiveName = [1.0, 2.0, 3.0, 4.0]
propertyWithLongDescriptiveName.withUnsafeMutableBufferPointer { y in
// ... mutate y ...
y[0] = 13
}
print(propertyWithLongDescriptiveName) // [13.0, 2.0, 3.0, 4.0]
withUnsafeMutableBufferPointer() calls the closure with an
UnsafeMutableBufferPointer to the element storage.
A UnsafeMutableBufferPointer is a RandomAccessCollection and
therefore offers an array-like interface.
No, the Swift compiler is not that smart. All you need is a small test to see what it does:
class MyClass {
var propertyWithLongDescriptiveName: [Float] = [1,2]
func foo() {
var y = propertyWithLongDescriptiveName
y[0] = 3 // copied an mutated
print(y) // [3,2]
print(propertyWithLongDescriptiveName) // [1,2]
}
}
let mc = MyClass()
mc.foo()
You have 2 optons:
Change propertyWithLongDescriptiveName to NSMutableArray, which is a reference type
Accept the overhead cost of copy-and-mutate to trade for readability of your algorithm. In many cases memory allocation cost is minimal compared to your algorithm's.

safely remove item while iterating backward in Swift 3

When I want to pass through and remove an item or items from an array (when certain conditions are met), I typically iterate backward in the C-style for-loop and remove the item by index, avoiding the problem of index numbers being changed of the next item to be processed, or the changing size of the list affecting how many times the loop is passed through. But the C for-loop has been removed in Swift 3.
Here is my Swift 2.3 code for the initialization of the loop:
for (var i = allowedItems.count - 1; i > -1; i -= 1)
Here is the monstrosity created by the Swift 3 converter:
for (i in ((-1 + 1)...allowedItems.count - 1).reversed())
This version does not compile however. ("Expected ',' separator" at the "in" operator).
I simplify the "-1 + 1" bit to zero:
for (i in (0...allowedItems.count - 1).reversed())
Now the error is "Expected Sequence expression for for-each loop".
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3, in which an index or counter variable is made available for use in specifying which item should be removed? This type of logic appears a number of places in my code so I want to make sure to find the best solution.
Thanks.
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3
The built-in way is:
for i in (0 ..< allowedItems.count).reversed()
The elegant way is:
for i in allowedItems.count >>> 0
(where >>> is the custom operator that I define here).
Use stride:
for i in stride(from: allowedItems.count - 1, through: 0, by: -1) {
}
What is the safe and hopefully reasonably elegant way of iterating
backward in Swift 3, in which an index or counter variable is made
available for use in specifying which item should be removed?
This doesn't answer the technical question, but possibly the underlying XY problem: have you considered simply filtering your array based on the criteria "when certain conditions are met"?
func certainConditionsForKeepingAreMet(_ element: YourElementType) -> Bool { /* ... */ }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
E.g.
var allowedItems = [1, 3 ,6, 2]
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool { return element < 3 }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
print(allowedItems) // [1, 2]
If you'd like to remove and use the removed elements (on-the-fly), you could simply pipe the elements that are to be removed to some "use this element" function, in the course of checking the conditions for the elements.
func doSomethingWith(_ element: Int) { print("Removed", element) }
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool {
if element >= 3 {
doSomethingWith(element)
return false
}
return true
}
var allowedItems = [1, 3 ,6, 2]
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
/* Removed 3
Removed 6 */
print(allowedItems) // [1, 2]

How do you assign a slice of numbers to an array in swift

x is an object that holds an array called point.
x implements the subscript operator so you can do things, like x[i] to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T> is not convertible to Int/Double.
Edit1:
Here is my object x:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x as [1.0,2.0,0.0]
I can get the first n elements via x[0...2].
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]. This does not work as can be seen in the answers. I want to update x without iteration (on my end) and by hiding the fact that x is not an array (even though it is not).
[0...2] is an array with one element which, at best, will be a Range<Int> from 0 through 2. You can't assign that to a slice containing, say, Ints.
x[0...2] on the other hand is (probably) a slice, and Sliceable only defines a get subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2, which at least is attempting to replace a range within x with the values of a similarly-sized collection - it still wouldn't work.
edit: as #rintaro points out, Array does support a setter subscript for ranges – so if x were a range you could do x[0...2] = Slice(0...2) – but it has to be a slice you assign, so I'd still go with replaceRange.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange, as long as your collection conforms to RangeReplaceableCollection (which, for example, Array does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y don't have to be the same size, the collection will expand/contract as necessary.
Also, y doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
You need to implement subscript(InvervalType) to handle the case of multiple assignments like this. That isn't done for you automatically.