Extend CollectionType add indexOutOfRange function - swift

I'm trying to add a function that tells me if an index is out of range in an array.
the startIndex and endIndex of CollectionType seem to be generic, so I'm trying to restrict the extension only when the index type is Int.
This code does not compile:
extension CollectionType where Index.Type is Int {
public func psoIndexOutOfRange(index: Index.Type) -> Bool{
return index < self.startIndex || index > self.endIndex
}
}
Is it possible? and what would be the correct way to add this.

Personally I think this would be better as an extension to Range, rather than to CollectionType:
extension Range where T: Comparable {
func contains(element: Generator.Element) -> Bool {
return element >= startIndex && element < endIndex
}
}
which you could call like so (indices returns the range from the collection’s start to end index):
[1,2,3].indices.contains(2)
Note, CollectionType (which Range conforms to) already has a contains method – but done via linear search. This overloads contains for ranges specifically to do it in constant time.
Also, if you're doing this in order to combine it with a subscript fetch, consider adding an optional fetch to make things easier:
extension CollectionType where Index: Comparable {
subscript(safe idx: Index) -> Generator.Element? {
guard indices.contains(idx) else { return nil }
return self[idx]
}
}
let a = [1,2,3]
a[safe: 4] // nil

How about:
extension CollectionType where Index: Comparable {
public func psoIndexOutOfRange(index: Index) -> Bool{
return index < self.startIndex || index >= self.endIndex
}
}
As #MartinR suggested, it's more general if you use Comparable instead of constraining Index to be of type Int.

Related

Why I cannot access self in this particular method but am allowed in others?

I have seen this question on SO but the answers there appear to be talking about functions that return self.
I am creating a class extension that starts like this
extension Sequence where Element: Comparable {
func normalize() -> [Element] {
let count = self.count
}
}
I need to get the number of elements self.count and in subsequent lines use the array elements, like self[i] but Swift complains saying that self nas no member called count and will not let me use self in any context.
How do I do that?
In swift, the count property is not defined in Sequence, but in Collection, so you need to extend from Collection instead.
extension Collection where Element: Comparable {
func normalize() -> [Element] {
let count = self.count
}
}
If you also need to access a value of the collection by indexes (self[i]), you should extend RandomAccessCollection instead, which provide both count (because a random access collection is a collection) and subscript function.
extension RandomAccessCollection where Element: Comparable {
func normalize() -> [Element] {
let count = self.count
let first = self[startIndex]
let second = self[index(startIndex, offsetBy: 1)]
return [first, second]
}
}
Note: As RandomAccessCollection indexes are not necessarily an int, you must use the index(_:offsetBy:) function to create an index that can be passed in the subscript method.

avoid force unwrapping inside a sort closure in Swift

I am trying to sort an array of objects, based on a property which is optional Int.
// sorting each language array based on most stars
groupedDictionariesValueUnwrapped.sort(by: { $0.stars! > $1.stars! })
Type of the array is [SingleRepository], and SingleRepository has an optional Int. stars: Int?
How should I avoid force unwrapping inside the sort?
You are sorting in descending order.
Use the nil coalescing operator ?? to safely unwrap the values and replace nil with Int.min to place the items at the end of the array:
// sorting each language array based on most stars
groupedDictionariesValueUnwrapped.sort(by: { ($0.stars ?? Int.min) > ($1.stars ?? Int.min) })
or use ?? Int.max to put them at the beginning.
If it makes sense for your class/struct, you can add conformance to Comparable to the type you want to sort:
extension MyClass: Comparable {
public static func ==(lhs: MyClass, rhs: MyClass) -> Bool {
return (lhs.stars ?? 0) == (rhs.stars ?? 0)
}
public static func <(lhs: MyClass, rhs: MyClass) -> Bool {
return (lhs.stars ?? 0) < (rhs.stars ?? 0)
}
}
You'd then be able to directly use the > operator function (conforming to Comparable brings up all other comparison operators >, >=, <=):
groupedDictionariesValueUnwrapped.sort(by: >)
By "making sense" I'm referring to the fact that conforming to Comparable based on the stars property adds value to the type definition (e.g. the type is named Rating and holds information about a user review).

Custom Collections Without Internal Collection Types?

I'd like to learn more about Swift's Collection Types by creating a custom collection.
The problem is that I can't find any examples of "custom" collection types that don't just use an internal array / dictionary.
These aren't helpful to me, because when it comes time to conform to the collection protocol, the examples just propagate the required methods to the army / dictionary.
That said, after looking through Wikipedia's List of Data Structures, I can't find any that meet the performance characteristics of collection types, that aren't just specialized arrays.
Does anyone know of a data structure that could be implemented with a custom collection type, without using an internal collection type?
EDIT
Collection protocol conformance requires that accesing the startIndex, the endIndex,and the elements of the collection be done constant time - O(1).
EDIT 2
The consensus in the comments seems to be that a LinkedList is a data structure that satisfies these characteristics. My LinkedList is defined as follows:
indirect enum LinkedList<T> {
case value(element: T, next: LinkedList<T>)
case end
}
extension LinkedList: Sequence {
func makeIterator() -> LinkedListIterator<T> {
return LinkedListIterator(current: self)
}
}
struct LinkedListIterator<T>: IteratorProtocol {
var current: LinkedList<T>
mutating func next() -> T? {
switch current {
case let .value(element, next):
current = next
return element
case .end:
return nil
}
}
}
What I still don't understand, is how subscript can be returned in constant time. For the LinkedList:
let data = LinkedList<Int>.value(element: 0, next: LinkedList<Int>.value(element: 1, next: LinkedList<Int>.value(element: 2, next: LinkedList<Int>.value(element: 3, next: LinkedList<Int>.end))))
Assume that I want access to the 3rd element in the Collection:
let example = data[2]
Currently, this is how I have implemented subscript:
subscript (position: Index) -> Element {
precondition(position < endIndex && position >= startIndex)
var iterator = makeIterator()
for i in 0 ..< position {
iterator.next()
if i + 1 == position {
return iterator.next()!
}
}
var zero = makeIterator()
return zero.next()!
}
Because the method's completion time depends on `i, it finishes in linear rather than constant time. How could such a constant time method be implemented?

Creating a ValidIndexCollection protocol in Swift 3

A while ago, I made a Binary Search Tree type in Swift that I wanted to conform to the Collection protocol. However, the endIndex requirement is a "past the end" index which isn't really appropriate for a tree because each index should hold a reference to its corresponding node for O(1) access. I ended up with an optional reference (being nil in the case of endIndex), but it involved a lot of boilerplate code that I'd rather avoid.
I decided to make a ValidIndexCollection protocol that looks like this:
/// A collection defined by valid indices only, rather than a
/// startIndex and a "past the end" endIndex.
protocol ValidIndexCollection: Collection {
associatedtype ValidIndex: Comparable
/// The first valid index if the collection is nonempty,
/// nil otherwise.
var firstValidIndex: ValidIndex? { get }
/// The last valid index if the collection is nonempty,
/// nil otherwise.
var lastValidIndex: ValidIndex? { get }
/// Returns the index right after the given index.
func validIndex(after index: ValidIndex) -> ValidIndex
/// Returns the element at the given index.
func element(at index: ValidIndex) -> Iterator.Element
}
Before I can extend this protocol to satisfy the Collection requirements, I have to introduce an appropriate index first:
enum ValidIndexCollectionIndex<ValidIndex: Comparable> {
case index(ValidIndex)
case endIndex
}
extension ValidIndexCollectionIndex: Comparable {
// ...
}
Now I can extend ValidIndexCollection:
// Implementing the Collection protocol requirements.
extension ValidIndexCollection {
typealias _Index = ValidIndexCollectionIndex<ValidIndex>
var startIndex: _Index {
return firstValidIndex.flatMap { .index($0) } ?? .endIndex
}
var endIndex: _Index {
return .endIndex
}
func index(after index: _Index) -> _Index {
guard case .index(let validIndex) = index else { fatalError("cannot increment endIndex") }
return .index(self.validIndex(after: validIndex))
}
subscript(index: _Index) -> Iterator.Element {
guard case .index(let validIndex) = index else { fatalError("cannot subscript using endIndex") }
return element(at: validIndex)
}
}
All seems well, the compiler doesn't complain! However, I tried to implement this protocol for a custom type:
struct CollectionOfTwo<Element> {
let first, second: Element
}
extension CollectionOfTwo: ValidIndexCollection {
var firstValidIndex: Int? { return 0 }
var lastValidIndex: Int? { return 1 }
func validIndex(after index: Int) -> Int {
return index + 1
}
subscript(index: Int) -> Element {
return index == 0 ? first : second
}
}
Now the compiler complains that CollectionOfTwo doesn't conform to Collection, Sequence, and IndexableBase. The error messages are very unhelpful, it's mostly messages like:
Protocol requires nested type SubSequence; do you want to add it?
or
Default type DefaultIndices<CollectionOfTwo<Element>> for associated type Indices (from protocol Collection) does not conform to IndexableBase
Is there any way to make this work? As far as I can tell, ValidIndexCollection satisfies the Collection requirements just fine.
Some things to note:
I called the ValidIndexCollection protocol method
validIndex(after:) that way because calling it index(after:)
resulted in a segmentation fault when trying to implement this protocol. That probably has something to do with the
index(after:) method from the Collection protocol.
For the same reason I used element(at:) instead of a subscript.
I used typealias _Index instead of typealias Index because the latter resulted in an error message saying "Index is ambiguous for type lookup in this context". Again, this probably has something to do with Collection's Index associated type.
Adding associatedtype Element to ValidIndexCollection and replacing all occurrences of Iterator.Element by Element fixed it.

iOS Swift Error: 'T' is not convertible to 'MirrorDisposition'

I am attempting to create an extension method for the Array type to allow for removing an item from an array
extension Array {
func remove(item: AnyObject) {
for var i = self.count - 1; i >= 0; i-- {
if self[i] == item {
self.removeAtIndex(i)
}
}
}
}
On the test condition if self[i] == item, I get the following error: 'T' is not convertible to 'MirrorDisposition'
I've tried many different things, which include:
Using generics: remove<T>(item: T)
Using the === operator, which just gives the error 'T' does not conform to protocol 'AnyObject'
I'm new to Swift, so this is where my knowledge runs out. Any suggestions would be greatly appreciated.
You are getting an error because the compiler can't guarantee that the element stored in your array can be compared with ==. You have to ensure that it the contained type is Equatable. However, there is no way to add a method to a generic class that is more restrictive than the class itself. It is better to implement it as a function:
func removeItem<T: Equatable>(item: T, var fromArray array: [T]) -> [T] {
for i in reverse(0 ..< array.count) {
if array[i] == item {
array.removeAtIndex(i)
}
}
return array
}
Or you could add it as a more generic extension:
extension Array {
mutating func removeObjectsPassingTest(test: (object: T) -> Bool) {
for var i : Int = self.count - 1; i >= 0; --i {
if test(object: self[i]) {
self.removeAtIndex(i)
}
}
}
}
Then you can do this:
var list: [Int] = [1,2,3,2,1]
list.removeObjectsPassingTest({$0 == 2})
The way I would write this function is like this:
mutating func remove<U where U : Equatable>(item: U) {
for var i = self.count - 1; i >= 0; i-- {
if self[i] as U == item {
self.removeAtIndex(i)
}
}
}
Be sure to decorate your function with mutating.
I would use a different type parameter U since you can't really change Array's type parameter to be Equatable. Then I would try to cast the items to U to do the comparison.
Of course, this will fail if you try to call this function with an Array that is instantiated with a non-equatable type.
This is not a solution but if you are trying to remove an item from an array, this is how I do it:
var numbers = [1, 2, 3, 4, 5]
if let possibleIndex = find(numbers, 1) {
numbers.removeAtIndex(possibleIndex)
}
The error message is confusing. The problem why it does not work is because Swift compiler can not find == operator for Array's element type T. For this to work T would need to conform to Equatable protocol.
I don't know what is MirrorDispsition, but I think the problem is that you can't always equate two objects in Array, because they are not guaranteed to be equatable.
Edit: Look at tng's solution. It will only work with equatable items, though.