Custom Index for Linked List in Swift - swift

Custom Index Type for Linked List
Swift 5.0, Xcode 10.3
I recently implemented a doubly linked list type in Swift. When I set out to make it, my goal was to give users most of the same ease of use as using an Array, but with the algorithmic complexities associated with doubly linked lists. With this goal in mind, I decided one of the primary ways I would achieve this would be making the Node type an implementation detail; out of sight and out of mind for the user. I also decided that LinkedList must be implemented as a struct so to provide support proper immutability/mutability.
Deciding on the semantics for the LinkedList type and its private Node type was quite tricky though. This was mainly due to LinkedList being a struct and Node being a class. Because of this, whenever a copy of a LinkedList value was made, mutating the copied linked list would also mutate the initial variable. For example, under the described circumstances, this would occur:
let list1 = LinkedList([1, 2, 3])
var list2 = list1
list2.append(4) // Mutates both list1 and list2
print(list1)
// Prints "[1, 2, 3, 4]"
This was, for obvious reasons, unintended and required me to put thought into the behaviour and semantics associated with making a copy of a LinkedList and mutation thereof. To combat this, in the only two mutating defined on LinkedList that were made accessible to the user, I checked whether or not the head node of the list was known to be uniquely referenced or not. If it was, the mutation would go under way as normal. But if it wasn't, a function would create a copy of all the nodes in list before mutating them. This would prevent mutating operations on an instance of LinkedList from affecting any other instance. This check before mutation effectively implemented copy-on-write semantics for LinkedList's nodes. With this, the previous example perform as expected:
let list1 = LinkedList([1, 2, 3])
var list2 = list1
list2.append(4) // Nodes are copied
print(list1)
// Prints "[1, 2, 3]"
print(list2)
// Prints "[1, 2, 3, 4]"
This seemed to provide a fix to the problem of shared references to nodes and their mutation therein quite nicely. Unfortunately, to my chagrin, I then realized that I had not tied up all of my loose ends. This is where I am currently stuck. To this point in time, my custom index type, LinkedList.Index, has been defined as following:
extension LinkedList: Collection {
//...
public struct Index: Comparable {
fileprivate weak var node: Node?
fileprivate var offset: Int
fileprivate init(node: Node?, offset: Int) {
self.node = node
self.offset = offset
}
public static func ==(lhs: Index, rhs: Index) -> Bool {
return lhs.offset == rhs.offset
}
public static func <(lhs: Index, rhs: Index) -> Bool {
return lhs.offset < rhs.offset
}
}
}
Let me break down some of the decisions I made while constructing this... Firstly, the offset property was put in to allow for comparison with other indices and to provide the ability to check if an index was within the bounds of a list. Secondly, the node property was essential to giving each Index actual meaning and usefulness. This meant that both index(after:) and index(before:) could rely on the node property's next and previous properties to provide their respective desired indices in O(1) time. To me, this in it of itself is seems to be a requirement for an index type of a linked list implementation. Presently, I do not think there is any way to circumvent this requirement of associating each index with its respective node. In testing, I also came across a bug wherein the list's node were being copied too frequently and also not being deallocated by ARC. I realized this was because of a strong reference being held to nodes by Index. To combat that, I made node a weak reference.
Before I state the problem I am having, here is my current code for LinkedList:
public struct LinkedList<Element> {
private var headNode: Node?
private var tailNode: Node?
public private(set) var count: Int = 0
public init() { }
}
//MARK: - LinkedList Node
extension LinkedList {
fileprivate class Node {
public var value: Element
public var next: Node?
public weak var previous: Node?
public init(value: Element) {
self.value = value
}
}
}
//MARK: - Initializers
public extension LinkedList {
private init(_ nodeChain: NodeChain?) {
guard let chain = nodeChain else {
return
}
headNode = chain.head
tailNode = chain.tail
count = chain.count
}
init<S>(_ sequence: S) where S: Sequence, S.Element == Element {
if let linkedList = sequence as? LinkedList<Element> {
self = linkedList
} else {
self = LinkedList(NodeChain(of: sequence))
}
}
}
//MARK: NodeChain
extension LinkedList {
private struct NodeChain {
let head: Node!
let tail: Node!
private(set) var count: Int
// Creates a chain of nodes from a sequence. Returns `nil` if the sequence is empty.
init?<S>(of sequence: S) where S: Sequence, S.Element == Element {
var iterator = sequence.makeIterator()
guard let firstValue = iterator.next() else {
return nil
}
var currentNode = Node(value: firstValue)
head = currentNode
count = 1
while let nextElement = iterator.next() {
let nextNode = Node(value: nextElement)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
count += 1
}
tail = currentNode
}
}
}
//MARK: - Copy Nodes
extension LinkedList {
private mutating func copyNodes(settingNodeAt index: Index, to value: Element) {
var currentIndex = startIndex
var currentNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
let newHeadNode = currentNode
currentIndex = self.index(after: currentIndex)
while currentIndex < endIndex {
let nextNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
currentIndex = self.index(after: currentIndex)
}
headNode = newHeadNode
tailNode = currentNode
}
#discardableResult
private mutating func copyNodes(removing range: Range<Index>) -> Range<Index> {
var currentIndex = startIndex
while range.contains(currentIndex) {
currentIndex = index(after: currentIndex)
}
guard let headValue = currentIndex.node?.value else {
self = LinkedList()
return endIndex..<endIndex
}
var currentNode = Node(value: headValue)
let newHeadNode = currentNode
var newCount = 1
var removedRange: Range<Index> = Index(node: currentNode, offset: 0)..<Index(node: currentNode, offset: 0)
currentIndex = index(after: currentIndex)
while currentIndex < endIndex {
guard !range.contains(currentIndex) else {
currentIndex = index(after: currentIndex)
continue
}
let nextNode = Node(value: currentIndex.node!.value)
if currentIndex == range.upperBound {
removedRange = Index(node: nextNode, offset: newCount)..<Index(node: nextNode, offset: newCount)
}
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
newCount += 1
currentIndex = index(after: currentIndex)
}
if currentIndex == range.upperBound {
removedRange = Index(node: nil, offset: newCount)..<Index(node: nil, offset: newCount)
}
headNode = newHeadNode
tailNode = currentNode
count = newCount
return removedRange
}
}
//MARK: - Computed Properties
public extension LinkedList {
var head: Element? {
return headNode?.value
}
var tail: Element? {
return tailNode?.value
}
}
//MARK: - Sequence Conformance
extension LinkedList: Sequence {
public typealias Element = Element
public __consuming func makeIterator() -> Iterator {
return Iterator(node: headNode)
}
public struct Iterator: IteratorProtocol {
private var currentNode: Node?
fileprivate init(node: Node?) {
currentNode = node
}
public mutating func next() -> Element? {
guard let node = currentNode else {
return nil
}
currentNode = node.next
return node.value
}
}
}
//MARK: - Collection Conformance
extension LinkedList: Collection {
public var startIndex: Index {
return Index(node: headNode, offset: 0)
}
public var endIndex: Index {
return Index(node: nil, offset: count)
}
public var first: Element? {
return head
}
public var isEmpty: Bool {
return count == 0
}
public func index(after i: Index) -> Index {
precondition(i.offset != endIndex.offset, "LinkedList index is out of bounds")
return Index(node: i.node?.next, offset: i.offset + 1)
}
public struct Index: Comparable {
fileprivate weak var node: Node?
fileprivate var offset: Int
fileprivate init(node: Node?, offset: Int) {
self.node = node
self.offset = offset
}
public static func ==(lhs: Index, rhs: Index) -> Bool {
return lhs.offset == rhs.offset
}
public static func <(lhs: Index, rhs: Index) -> Bool {
return lhs.offset < rhs.offset
}
}
}
//MARK: - MutableCollection Conformance
extension LinkedList: MutableCollection {
public subscript(position: Index) -> Element {
get {
precondition(position.offset != endIndex.offset, "Index out of range")
guard let node = position.node else {
preconditionFailure("LinkedList index is invalid")
}
return node.value
}
set {
precondition(position.offset != endIndex.offset, "Index out of range")
// Copy-on-write semantics for nodes
if !isKnownUniquelyReferenced(&headNode) {
copyNodes(settingNodeAt: position, to: newValue)
} else {
position.node?.value = newValue
}
}
}
}
//MARK: LinkedList Specific Operations
public extension LinkedList {
mutating func prepend(_ newElement: Element) {
replaceSubrange(startIndex..<startIndex, with: CollectionOfOne(newElement))
}
mutating func prepend<S>(contentsOf newElements: __owned S) where S: Sequence, S.Element == Element {
replaceSubrange(startIndex..<startIndex, with: newElements)
}
#discardableResult
mutating func popFirst() -> Element? {
if isEmpty {
return nil
}
return removeFirst()
}
#discardableResult
mutating func popLast() -> Element? {
guard isEmpty else {
return nil
}
return removeLast()
}
}
//MARK: - BidirectionalCollection Conformance
extension LinkedList: BidirectionalCollection {
public var last: Element? {
return tail
}
public func index(before i: Index) -> Index {
precondition(i.offset != startIndex.offset, "LinkedList index is out of bounds")
if i.offset == count {
return Index(node: tailNode, offset: i.offset - 1)
}
return Index(node: i.node?.previous, offset: i.offset - 1)
}
}
//MARK: - RangeReplaceableCollection Conformance
extension LinkedList: RangeReplaceableCollection {
public mutating func append<S>(contentsOf newElements: __owned S) where S: Sequence, Element == S.Element {
replaceSubrange(endIndex..<endIndex, with: newElements)
}
public mutating func replaceSubrange<S, R>(_ subrange: R, with newElements: __owned S) where S: Sequence, R: RangeExpression, Element == S.Element, Index == R.Bound {
var range = subrange.relative(to: indices)
precondition(range.lowerBound >= startIndex && range.upperBound <= endIndex, "Subrange bounds are out of range")
// If range covers all elements and the new elements are a LinkedList then set references to it
if range.lowerBound == startIndex, range.upperBound == endIndex, let linkedList = newElements as? LinkedList {
self = linkedList
return
}
var newElementsCount = 0
// There are no new elements, so range indicates deletion
guard let nodeChain = NodeChain(of: newElements) else {
// If there is nothing in the removal range
// This also covers the case that the linked list is empty because this is the only possible range
guard range.lowerBound != range.upperBound else {
return
}
// Deletion range spans all elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nil
tailNode = nil
count = 0
return
}
// Copy-on-write semantics for nodes and remove elements in range
guard isKnownUniquelyReferenced(&headNode) else {
copyNodes(removing: range)
return
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count = count - (range.upperBound.offset - range.lowerBound.offset)
}
// Move head up if deletion starts at start index
if range.lowerBound == startIndex {
// Can force unwrap node since the upperBound is not the end index
headNode = range.upperBound.node!
headNode!.previous = nil
// Move tail back if deletion ends at end index
} else if range.upperBound == endIndex {
// Can force unwrap since lowerBound index must have an associated element
tailNode = range.lowerBound.node!.previous
tailNode!.next = nil
// Deletion range is in the middle of the linked list
} else {
// Can force unwrap all bound nodes since they both must have elements
range.upperBound.node!.previous = range.lowerBound.node!.previous
range.lowerBound.node!.previous!.next = range.upperBound.node!
}
return
}
// Obtain the count of the new elements from the node chain composed from them
newElementsCount = nodeChain.count
// Replace entire content of list with new elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nodeChain.head
tailNode = nodeChain.tail
count = nodeChain.count
return
}
// Copy-on-write semantics for nodes before mutation
if !isKnownUniquelyReferenced(&headNode) {
range = copyNodes(removing: range)
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count += nodeChain.count - (range.upperBound.offset - range.lowerBound.offset)
}
// Prepending new elements
guard range.upperBound != startIndex else {
headNode?.previous = nodeChain.tail
nodeChain.tail.next = headNode
headNode = nodeChain.head
return
}
// Appending new elements
guard range.lowerBound != endIndex else {
tailNode?.next = nodeChain.head
nodeChain.head.previous = tailNode
tailNode = nodeChain.tail
return
}
if range.lowerBound == startIndex {
headNode = nodeChain.head
}
if range.upperBound == endIndex {
tailNode = nodeChain.tail
}
range.lowerBound.node!.previous!.next = nodeChain.head
range.upperBound.node!.previous = nodeChain.tail
}
}
//MARK: - ExpressibleByArrayLiteral Conformance
extension LinkedList: ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Element
public init(arrayLiteral elements: ArrayLiteralElement...) {
self.init(elements)
}
}
//MARK: - CustomStringConvertible Conformance
extension LinkedList: CustomStringConvertible {
public var description: String {
return "[" + lazy.map { "\($0)" }.joined(separator: ", ") + "]"
}
}
Note: if/when I do update my code, the up-to-date version can be found here.
My Problem
The current problem I am experiencing is with Index instances. When an index is provided either to a method, as is the case currently, the method has no way of knowing and checking whether or not that index/node belongs to that specific LinkedList instance. That allows for bugs such as this:
let immutableList: LinkedList = [1, 2, 3, 4]
var mutableList: LinkedList = [5, 6, 7, 8]
let immutableIndex = immutableList.index(after: immutableList.startIndex)
mutableList[immutableIndex] = 0
print("Immutable List:", immutableList)
print("Mutable List:", mutableList)
// Prints:
// Immutable List: [1, 0, 3, 4]
// Mutable List: [5, 6, 7, 8]
All methods that deal with Index must have a way to confirm that the index they are dealing with contains a node owned by the current LinkedList instance, though I have no idea how I would be able to do this.
Furthermore, indices' offset invalidate after mutation to their node's parent list, thus causing absurd situations like this wherein the indices are said to be equal:
var list: LinkedList = [1, 2, 3, 4]
let idx1 = list.index(list.startIndex, offsetBy: 2) // Index to node with value of 3 and offset of 2
list.remove(at: list.index(before: idx1))
print(list)
// Prints: "[1, 3, 4]"
let idx2 = list.index(before: list.endIndex) // Index to node with value of 4 and offset of 2
print(idx1 == idx2)
// Prints: "true"
print(Array(list[idx1...idx2]))
// Prints: "[3]"
In the previous example, because, upon mutation of a LinkedList, instances of its indices' offsets are not updated, though they still have a weak reference to their associated node, many unintended consequences and incorrect behaviour can arise.
When creating the Index type initially, I was hard pressed to find similar examples to mine online and as a result I am not totally sure whether things like startIndex and endIndex and how index(before:) and index(after:) handle them are the optimal/proper way. I am looking for input on how I can go about fixing all of these problems brought on by LinkedList.Index and properly implement it. Any and all input is appreciated!

Let's address the second problem first:
Furthermore, indices' offset invalidate after mutation to their node's parent list, thus causing absurd situations ...
That is to be expected with all collections. From Collections:
Saved indices may become invalid as a result of mutating operations.
Using an invalidated index is undefined behavior, and anything can happen: An unexpected result, a fatal error, ... Here is a simple example for Swift strings:
var s = "a🇩🇪bcd"
let i = s.firstIndex(of: "🇩🇪")!
s.remove(at: s.startIndex) // invalidates `i`
s.remove(at: i)
print(s) // \360cd
Now the first (main?) problem:
... the method has no way of knowing and checking whether or not that index/node belongs to that specific LinkedList instance.
Quoting from Collections again:
You can pass only valid indices to collection operations. You can find a complete set of a collection’s valid indices by starting with the collection’s startIndex property and finding every successor up to, and including, the endIndex property. All other values of the Index type, such as the startIndex property of a different collection, are invalid indices for this collection.
In your case
mutableList[immutableIndex] = 0
immutableIndex is not a valid index for mutableList, so this is again undefined behavior. A user of your library can not expect that this does anything sensible.
A possible way to protect against this misuse could be to store in the LinkedList.Index a (weak) pointer to the head node of the linked list, and verify that owner in the accessor methods (subscripts).

Related

How can I implement a CountedSet (NSCountedSet) in Swift?

Create a generic CountedSet struct that is constrained to Hashable elements. A counted set is an unordered collection of unique elements that may appear more than once in the collection. Use a private dictionary as your backing storage for set members and their counts.
struct CountedSet<Element> {
private(set) var elements: [Element]
mutating func insert(_ element: Element) {
elements.append(element)
}
mutating func remove() -> Element? {
guard elements.isEmpty == false else { return nil}
return elements.removeFirst()
}
subscript(_ member: Element) -> Int {
return 0
}
}
I don't understand what the real objective is here. The instructions are very confusing at least to me.
1) Make your generic struct element conform to Hashable, this is necessary because the dictionary keys are required to conform to Hashable.
struct CountedSet<Element: Hashable>
2) The backing storage you have used is an ordered array, not a dictionary and you need to initialize it with an empty one.
private(set) var elements: [Element: Int] = [:]
3) Your subscript method you need to return the count for the counted set member or zero if it is nil.
return elements[member] ?? 0
4) Your Insert and Remove methods need to first check the count of a member in the backing dictionary before adding or removing an element from it.
So your CountedSet should look like this:
struct CountedSet<Element: Hashable> {
private(set) var elements: [Element: Int] = [:]
mutating func insert(_ member: Element) {
elements[member, default: 0] += 1
}
mutating func remove(_ member: Element) -> Element? {
guard var count = elements[member], count > 0 else { return nil }
count -= 1
elements[member] = count == 0 ? nil : count
return member
}
subscript(_ member: Element) -> Int {
elements[member] ?? 0
}
}
var countedSet = CountedSet<Int>()
countedSet.insert(3)
countedSet.insert(3)
countedSet.insert(4)
countedSet.elements // [4: 1, 3: 2]
countedSet.remove(4)
countedSet.elements // [3: 2]
countedSet.remove(4) // nil
Expanding on that you can also make your CountedSet conform to ExpressibleByArrayLiteral to allow you to initialize your CountedSet with an array and CustomStringConvertible to allow you to print its elements:
extension CountedSet: ExpressibleByArrayLiteral, CustomStringConvertible {
typealias ArrayLiteralElement = Element
init<S: Sequence>(_ sequence: S) where S.Element == Element {
self.elements = sequence.reduce(into: [:]) { $0[$1, default: 0] += 1 }
}
init(arrayLiteral elements: Element...) { self.init(elements) }
var description: String { .init(describing: elements) }
}
var countedSet: CountedSet = [1,2,2,3,3,3,4,4,5,5,5]
print(countedSet) // "[5: 3, 2: 2, 3: 3, 4: 2, 1: 1]\n"

Find first matching object in array given starting index

I have an array of objects
var arrayOfObjects: [Object]?
And they all have a property called depth. I want to find the very next object in that array that has the same depth with a specific object I know the index of:
[
...objects_before...,
object_I_know: {depth:3},
...objects_after...
]
Is there a more efficient way other than using a for loop starting from the object_I_know index, and traversing down until it finds one?
let nextIndex: Int? = (givenIndex ..< array.endIndex).first { index in
return array[index].depth == array[givenIndex].depth
}
The item with the object with the same depth would be at that nextIndex if there is one
let nextObject: Object? = (nextIndex == nil) ? nil : array[nextIndex!]
Here's a sample model I came up with for testing:
struct S {
let id: Int
let depth: Int
}
var id = 0
let getID: () -> Int = { defer { id += 1 }; return id }
let objects = [
S(id: getID(), depth: 1),
S(id: getID(), depth: 3),
S(id: getID(), depth: 2),
S(id: getID(), depth: 3),
S(id: getID(), depth: 4),
]
Here's a solution that account for the situations in which there are no elements which match the predicate, or only 1 such element:
let isDepth3: (S) -> Bool = { $0.depth == 3 }
// Get the index of the first item (can be nil)
let indexOfFirstDepth3 = objects.index(where: isDepth3)
// Get the index after that (can be nil), so that we can exclude everything before it
let firstIndexOfRemainingItems = indexOfFirstDepth3.flatMap { objects.index($0, offsetBy: +1, limitedBy: objects.endIndex) }
let indexOfSecondDepth3 = firstIndexOfRemainingItems.flatMap {
// Slice the `objects` array, to omit all the items before up to and including the first depth 3 item.
// Then find the index of the next next 3 item thereafter.
return objects[$0...].index(where: isDepth3)
}
// Print results
func stringifyOptional<T>(_ item: T?) -> String {
return item.map{ String(describing: $0) } ?? "nil"
}
print("First item with depth 3 is \(stringifyOptional(indexOfFirstDepth3.map{ objects[$0] })) at index \(stringifyOptional(indexOfFirstDepth3))")
print("Second item with depth 3 is \(stringifyOptional(indexOfSecondDepth3.map{ objects[$0] })) at index \(stringifyOptional(indexOfFirstDepth3))")
If you're sure that you'll have 2 such elements, and you're sure that force unwrapping will be safe, then this can be simplified dramatically:
let isDepth3: (S) -> Bool = { $0.depth == 3 }
let indexOfFirstDepth3 = objects.index(where: isDepth3)!
let indexOfSecondDepth3 = objects[indexOfFirstDepth3...].index(where: isDepth3)!
// Just printing the result
print("First item with depth 3 is \(objects[indexOfFirstDepth3]) at index \(indexOfFirstDepth3)")
print("Second item with depth 3 is \(objects[indexOfFirstDepth3])) at index \(indexOfFirstDepth3)")
Context
struct DepthObject { let depth: Int }
let objs = [a, b, c, d ,e]
let index = 1 //predetermined index
let depthToFind = objs[index].depth
let startIndex = index + 1
let remainingArray = objs[startIndex...] //The slice we want to work with
One way
let aMessage: String? = remainingArray
.first { $0.depth == depthToFind }
.flatMap { "The world is yours \($0)" }
Decide based on it
if let nextDepthObject = remainingArray.first(where: { $0.depth == depthToFind }) {
//Found the next one!
} else {
//Didn't find it!
}
Loop it
var nextDepthObject: DepthObject? = nil
for sliceDepthObject in remainingArray {
if sliceDepthObject.depth == depthToFind {
nextDepthObject = sliceDepthObject
break
}
}
Implementing a particular approach
func nextDepthObject(within array: Array<DepthObject>, startingAt index: Int) -> DepthObject? {
guard index + 1 < array.count && index < array.count else {
return nil
}
let depthToFind = array[index].depth
let suffixArray = array[(index + 1)...]
return suffixArray.first { $0.depth == depthToFind }
}
let theNextOne: DepthObject? = nextDepthObject(within: objs, startingAt: index)
You can add an extension over Collection (which Array conforms to):
extension Collection {
func next(startingWith next: Self.Index, where match: (Element) -> Bool) -> Element? {
guard next < endIndex else { return nil }
return self[next..<endIndex].first(where: match)
}
}
You'd use it like this:
let nextMatch = arrayOfObjects.next(startingWith: foundIndex+1) { $0.depth == searchedDepth }
class Object {
var name: String
var depth: Float
init(name: String, depth: Float) {
self.name = name
self.depth = depth
}
}
let o1 = Object(name: "object1", depth: 10)
let o2 = Object(name: "object2", depth: 12)
let o3 = Object(name: "object3", depth: 4)
let o4 = Object(name: "object4", depth: 12)
let o5 = Object(name: "object5", depth: 14)
let array = [o1, o2, o3, o4, o5]
let knownIndex = 1
let knownDepth = array[knownIndex].depth
var searchResults = [Object]()
// iterate through the second half of the array after the known
// index and break the loop when a match is found
for i in knownIndex + 1..<array.count {
if array[i].depth == knownDepth {
searchResults = [array[i]]
break
}
}
// after the loop is finished (either by going all the way to the
// end or breaking after a match is found), check your search results
if searchResults.count > 0 {
print("match found: \(searchResults[0].name)")
} else {
print("no match found")
}
index(where:) uses a loop also, unbeknownst to the commenter, except that the compiler does it for you behind the scenes. index(where:) also loops through the entire array which is not very efficient if you already know the starting index (which OP does).

Shuffle Plist Array in Swift [duplicate]

.shuffle() and .shuffled() are part of Swift
Original historic question:
How do I randomize or shuffle the elements within an array in Swift? For example, if my array consists of 52 playing cards, I want to shuffle the array in order to shuffle the deck.
This answer details how to shuffle with a fast and uniform algorithm (Fisher-Yates) in Swift 4.2+ and how to add the same feature in the various previous versions of Swift. The naming and behavior for each Swift version matches the mutating and nonmutating sorting methods for that version.
Swift 4.2+
shuffle and shuffled are native starting Swift 4.2. Example usage:
let x = [1, 2, 3].shuffled()
// x == [2, 3, 1]
let fiveStrings = stride(from: 0, through: 100, by: 5).map(String.init).shuffled()
// fiveStrings == ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffle()
// numbers == [3, 2, 1, 4]
Swift 4.0 and 4.1
These extensions add a shuffle() method to any mutable collection (arrays and unsafe mutable buffers) and a shuffled() method to any sequence:
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Same usage as in Swift 4.2 examples above.
Swift 3
These extensions add a shuffle() method to any mutable collection and a shuffled() method to any sequence:
extension MutableCollection where Indices.Iterator.Element == Index {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 3.2
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
self.swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Iterator.Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Same usage as in Swift 4.2 examples above.
Swift 2
(obsolete language: you can't use Swift 2.x to publish on iTunes Connect starting July 2018)
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled.
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
Usage:
[1, 2, 3].shuffle()
// [2, 3, 1]
let fiveStrings = 0.stride(through: 100, by: 5).map(String.init).shuffle()
// ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffleInPlace()
// [3, 2, 1, 4]
Swift 1.2
(obsolete language: you can't use Swift 1.x to publish on iTunes Connect starting July 2018)
shuffle as a mutating array method
This extension will let you shuffle a mutable Array instance in place:
extension Array {
mutating func shuffle() {
if count < 2 { return }
for i in 0..<(count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
swap(&self[i], &self[j])
}
}
}
var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.shuffle() // e.g., numbers == [6, 1, 8, 3, 2, 4, 7, 5]
shuffled as a non-mutating array method
This extension will let you retrieve a shuffled copy of an Array instance:
extension Array {
func shuffled() -> [T] {
if count < 2 { return self }
var list = self
for i in 0..<(list.count - 1) {
let j = Int(arc4random_uniform(UInt32(list.count - i))) + i
swap(&list[i], &list[j])
}
return list
}
}
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let mixedup = numbers.shuffled() // e.g., mixedup == [6, 1, 8, 3, 2, 4, 7, 5]
Edit: As noted in other answers, Swift 4.2 finally adds random number generation to the standard library, complete with array shuffling.
However, the GKRandom / GKRandomDistribution suite in GameplayKit can still be useful with the new RandomNumberGenerator protocol — if you add extensions to the GameplayKit RNGs to conform to the new standard library protocol, you can easily get:
sendable RNGs (that can reproduce a "random" sequence when needed for testing)
RNGs that sacrifice robustness for speed
RNGs that produce non-uniform distributions
...and still make use of the nice new "native" random APIs in Swift.
The rest of this answer concerns such RNGs and/or their use in older Swift compilers.
There are some good answers here already, as well as some good illustrations of why writing your own shuffle can be error-prone if you're not careful.
In iOS 9, macOS 10.11, and tvOS 9 (or later), you don't have to write your own. There's an efficient, correct implementation of Fisher-Yates in GameplayKit (which, despite the name, is not just for games).
If you just want a unique shuffle:
let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
If you want to be able to replicate a shuffle or series of shuffles, choose and seed a specific random source; e.g.
let lcg = GKLinearCongruentialRandomSource(seed: mySeedValue)
let shuffled = lcg.arrayByShufflingObjects(in: array)
In iOS 10 / macOS 10.12 / tvOS 10, there's also a convenience syntax for shuffling via an extension on NSArray. Of course, that's a little cumbersome when you're using a Swift Array (and it loses its element type on coming back to Swift):
let shuffled1 = (array as NSArray).shuffled(using: random) // -> [Any]
let shuffled2 = (array as NSArray).shuffled() // use default random source
But it's pretty easy to make a type-preserving Swift wrapper for it:
extension Array {
func shuffled(using source: GKRandomSource) -> [Element] {
return (self as NSArray).shuffled(using: source) as! [Element]
}
func shuffled() -> [Element] {
return (self as NSArray).shuffled() as! [Element]
}
}
let shuffled3 = array.shuffled(using: random)
let shuffled4 = array.shuffled()
In Swift 2.0, GameplayKit may come to the rescue! (supported by iOS9 or later)
import GameplayKit
func shuffle() {
array = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(array)
}
Here's something possibly a little shorter:
sorted(a) {_, _ in arc4random() % 2 == 0}
Taking Nate's algorithm I wanted to see how this would look with Swift 2 and protocol extensions.
This is what I came up with.
extension MutableCollectionType where Self.Index == Int {
mutating func shuffleInPlace() {
let c = self.count
for i in 0..<(c - 1) {
let j = Int(arc4random_uniform(UInt32(c - i))) + i
swap(&self[i], &self[j])
}
}
}
extension MutableCollectionType where Self.Index == Int {
func shuffle() -> Self {
var r = self
let c = self.count
for i in 0..<(c - 1) {
let j = Int(arc4random_uniform(UInt32(c - i))) + i
swap(&r[i], &r[j])
}
return r
}
}
Now, any MutableCollectionType can use these methods given it uses Int as an Index
As of swift 4.2 there are two handy functions:
// shuffles the array in place
myArray.shuffle()
and
// generates a new array with shuffled elements of the old array
let newArray = myArray.shuffled()
In my case, I had some problems of swapping objects in Array. Then I scratched my head and went for reinventing the wheel.
// swift 3.0 ready
extension Array {
func shuffled() -> [Element] {
var results = [Element]()
var indexes = (0 ..< count).map { $0 }
while indexes.count > 0 {
let indexOfIndexes = Int(arc4random_uniform(UInt32(indexes.count)))
let index = indexes[indexOfIndexes]
results.append(self[index])
indexes.remove(at: indexOfIndexes)
}
return results
}
}
This is a version of Nate's implementation of the Fisher-Yates shuffle for Swift 4
(Xcode 9).
extension MutableCollection {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
for i in indices.dropLast() {
let diff = distance(from: i, to: endIndex)
let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff))))
swapAt(i, j)
}
}
}
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Element] {
var list = Array(self)
list.shuffle()
return list
}
}
The changes are:
The constraint Indices.Iterator.Element == Index is now part
of the Collection protocol, and need not be imposed on the
extension anymore.
Exchanging elements must done by calling swapAt() on the collection,
compare SE-0173 Add MutableCollection.swapAt(_:_:).
Element is an alias for Iterator.Element.
Swift 4
Shuffle the elements of an array in a for loop where i is the mixing ratio
var cards = [Int]() //Some Array
let i = 4 // is the mixing ratio
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: Int(arc4random_uniform(UInt32(cards.count))))
cards.insert(card, at: Int(arc4random_uniform(UInt32(cards.count))))
}
}
Or with extension Int
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: cards.count.arc4random)
cards.insert(card, at: cards.count.arc4random)
}
}
extension Int {
var arc4random: Int {
if self > 0 {
print("Arc for random positiv self \(Int(arc4random_uniform(UInt32(self))))")
return Int(arc4random_uniform(UInt32(self)))
} else if self < 0 {
print("Arc for random negotiv self \(-Int(arc4random_uniform(UInt32(abs(self)))))")
return -Int(arc4random_uniform(UInt32(abs(self))))
} else {
print("Arc for random equal 0")
return 0
}
}
}
This is what I use:
func newShuffledArray(array:NSArray) -> NSArray {
var mutableArray = array.mutableCopy() as! NSMutableArray
var count = mutableArray.count
if count>1 {
for var i=count-1;i>0;--i{
mutableArray.exchangeObjectAtIndex(i, withObjectAtIndex: Int(arc4random_uniform(UInt32(i+1))))
}
}
return mutableArray as NSArray
}
Swift 3 solution, following #Nate Cook answer: (work if the index starts with 0, see comments below)
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
} }
extension MutableCollection where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
let countInt = count as! Int
for i in 0..<countInt - 1 {
let j = Int(arc4random_uniform(UInt32(countInt - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
This is how its done in a Simplest way.import Gamplaykit to your VC and use the below code. Tested in Xcode 8.
import GameplayKit
let array: NSArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
override func viewDidLoad() {
super.viewDidLoad()
print(array.shuffled())
}
If you want to get a shuffled String from an Array you can use below code..
func suffleString() {
let ShuffleArray = array.shuffled()
suffleString.text = ShuffleArray.first as? String
print(suffleString.text!)
}
With Swift 3, if you want to shuffle an array in place or get a new shuffled array from an array, AnyIterator can help you. The idea is to create an array of indices from your array, to shuffle those indices with an AnyIterator instance and swap(_:_:) function and to map each element of this AnyIterator instance with the array's corresponding element.
The following Playground code shows how it works:
import Darwin // required for arc4random_uniform
let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
var indexArray = Array(array.indices)
var index = indexArray.endIndex
let indexIterator: AnyIterator<Int> = AnyIterator {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
let newArray = indexIterator.map { array[$0] }
print(newArray) // may print: ["Jock", "Ellie", "Sue Ellen", "JR", "Pamela", "Bobby"]
You can refactor the previous code and create a shuffled() function inside an Array extension in order to get a new shuffled array from an array:
import Darwin // required for arc4random_uniform
extension Array {
func shuffled() -> Array<Element> {
var indexArray = Array<Int>(indices)
var index = indexArray.endIndex
let indexIterator = AnyIterator<Int> {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
return indexIterator.map { self[$0] }
}
}
Usage:
let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
let newArray = array.shuffled()
print(newArray) // may print: ["Bobby", "Pamela", "Jock", "Ellie", "JR", "Sue Ellen"]
let emptyArray = [String]()
let newEmptyArray = emptyArray.shuffled()
print(newEmptyArray) // prints: []
As an alternative to the previous code, you can create a shuffle() function inside an Array extension in order to shuffle an array in place:
import Darwin // required for arc4random_uniform
extension Array {
mutating func shuffle() {
var indexArray = Array<Int>(indices)
var index = indexArray.endIndex
let indexIterator = AnyIterator<Int> {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
self = indexIterator.map { self[$0] }
}
}
Usage:
var mutatingArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
mutatingArray.shuffle()
print(mutatingArray) // may print ["Sue Ellen", "Pamela", "Jock", "Ellie", "Bobby", "JR"]
In Swift 4.2, there is now a method for both a mutable shuffle and immutable shuffled. You can read more about the random generation and array stuff here.
You can use generic swap function as well and implement mentioned Fisher-Yates:
for idx in 0..<arr.count {
let rnd = Int(arc4random_uniform(UInt32(idx)))
if rnd != idx {
swap(&arr[idx], &arr[rnd])
}
}
or less verbose:
for idx in 0..<steps.count {
swap(&steps[idx], &steps[Int(arc4random_uniform(UInt32(idx)))])
}
works!!. organisms is the array to shuffle.
extension Array
{
/** Randomizes the order of an array's elements. */
mutating func shuffle()
{
for _ in 0..<10
{
sort { (_,_) in arc4random() < arc4random() }
}
}
}
var organisms = [
"ant", "bacteria", "cougar",
"dog", "elephant", "firefly",
"goat", "hedgehog", "iguana"]
print("Original: \(organisms)")
organisms.shuffle()
print("Shuffled: \(organisms)")
Working Array Extension (mutating & non-mutating)
Swift 4.1 / Xcode 9
The top answer is deprecated, so I took it upon myself to create my own extension to shuffle an array in the newest version of Swift, Swift 4.1 (Xcode 9):
extension Array {
// Non-mutating shuffle
var shuffled : Array {
let totalCount : Int = self.count
var shuffledArray : Array = []
var count : Int = totalCount
var tempArray : Array = self
for _ in 0..<totalCount {
let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
let randomElement : Element = tempArray.remove(at: randomIndex)
shuffledArray.append(randomElement)
count -= 1
}
return shuffledArray
}
// Mutating shuffle
mutating func shuffle() {
let totalCount : Int = self.count
var shuffledArray : Array = []
var count : Int = totalCount
var tempArray : Array = self
for _ in 0..<totalCount {
let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
let randomElement : Element = tempArray.remove(at: randomIndex)
shuffledArray.append(randomElement)
count -= 1
}
self = shuffledArray
}
}
Call Non-Mutating Shuffle [Array] -> [Array]:
let array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
print(array.shuffled)
This prints array in a random order.
Call Mutating Shuffle [Array] = [Array]:
var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
array.shuffle()
// The array has now been mutated and contains all of its initial
// values, but in a randomized shuffled order
print(array)
This prints array in its current order, which has already been randomly shuffled.
Hopes this works for everybody, if you have any questions, suggestions, or comments, feel free to ask!
In SWIFT 4
func createShuffledSequenceOfNumbers(max:UInt)->[UInt] {
var array:[UInt]! = []
var myArray:[UInt]! = []
for i in 1...max {
myArray.append(i)
}
for i in 1...max {
array.append(i)
}
var tempArray:[Int]! = []
for index in 0...(myArray.count - 1) {
var isNotFinded:Bool = true
while(isNotFinded){
let randomNumber = arc4random_uniform(UInt32(myArray.count))
let randomIndex = Int(randomNumber)
if(!tempArray.contains(randomIndex)){
tempArray.append(randomIndex)
array[randomIndex] = myArray[index]
isNotFinded = false
}
}
}
return array
}
If you want to use simple Swift For loop function use this ->
var arrayItems = ["A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "X9", "Y10", "Z11"]
var shuffledArray = [String]()
for i in 0..<arrayItems.count
{
let randomObject = Int(arc4random_uniform(UInt32(items.count)))
shuffledArray.append(items[randomObject])
items.remove(at: randomObject)
}
print(shuffledArray)
Swift Array suffle using extension ->
extension Array {
// Order Randomize
mutating func shuffle() {
for _ in 0..<count {
sort { (_,_) in arc4random() < arc4random() }
}
}
}
This is how to shuffle one array with a seed in Swift 3.0.
extension MutableCollection where Indices.Iterator.Element == Index {
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
srand48(seedNumber)
let number:Int = numericCast(unshuffledCount)
let r = floor(drand48() * Double(number))
let d: IndexDistance = numericCast(Int(r))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
swap(&self[firstUnshuffled], &self[i])
}
}
}
let shuffl = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: arrayObject)
This is what I use:
import GameplayKit
extension Collection {
func shuffled() -> [Iterator.Element] {
let shuffledArray = (self as? NSArray)?.shuffled()
let outputArray = shuffledArray as? [Iterator.Element]
return outputArray ?? []
}
mutating func shuffle() {
if let selfShuffled = self.shuffled() as? Self {
self = selfShuffled
}
}
}
// Usage example:
var numbers = [1,2,3,4,5]
numbers.shuffle()
print(numbers) // output example: [2, 3, 5, 4, 1]
print([10, "hi", 9.0].shuffled()) // output example: [hi, 10, 9]
Simple Example:
extension Array {
mutating func shuffled() {
for _ in self {
// generate random indexes that will be swapped
var (a, b) = (Int(arc4random_uniform(UInt32(self.count - 1))), Int(arc4random_uniform(UInt32(self.count - 1))))
if a == b { // if the same indexes are generated swap the first and last
a = 0
b = self.count - 1
}
swap(&self[a], &self[b])
}
}
}
var array = [1,2,3,4,5,6,7,8,9,10]
array.shuffled()
print(array) // [9, 8, 3, 5, 7, 6, 4, 2, 1, 10]
Here's some code that runs in playground. You won't need to import Darwin in an actual Xcode project.
import darwin
var a = [1,2,3,4,5,6,7]
func shuffle<ItemType>(item1: ItemType, item2: ItemType) -> Bool {
return drand48() > 0.5
}
sort(a, shuffle)
println(a)
It stop at "swap(&self[i], &self[j])" when I upgrade the xCode version to 7.4 beta.
fatal error: swapping a location with itself is not supported
I found the reason that i = j (function of swap will exploded)
So I add a condition as below
if (i != j){
swap(&list[i], &list[j])
}
YA! It's OK for me.

Getting a random element in array by a generic function

func ramElment<X, T: CollectionType >(list: T) -> X {
let len = UInt32(list.count)
let element = arc4random_uniform(len)
return list[element]
}
it pops up:
error: cannot invoke initializer for type UInt32 with an argument list of type '(T.Index.Distance)'
let len = UInt32(list.count)
I have checked the T.Index.Distance is Int type. but why can't i change the type to UInt32?
thanks!
The Index of a CollectionType is
a ForwardIndexType:
public protocol ForwardIndexType : _Incrementable {
// ...
typealias Distance : _SignedIntegerType = Int
// ...
}
This means that the associated type Distance must conform to _SignedIntegerType, and (by default) is Int unless declared (or inferred)
otherwise.
Example: The following is a valid type conforming to ForwardIndexType,
with Distance == Int16:
struct MyIndex : ForwardIndexType {
var value : Int16
func advancedBy(n: Int16) -> MyIndex {
return MyIndex(value: value + n)
}
func distanceTo(end: MyIndex) -> Int16 {
return end.value - value
}
func successor() -> MyIndex {
return MyIndex(value: value + 1)
}
}
func ==(lhs : MyIndex, rhs : MyIndex) -> Bool {
return lhs.value == rhs.value
}
And here is a (for demonstration purposes, otherwise pretty useless)
type conforming to CollectionType with Index == MyIndex,
Index.Distance == Int16:
struct MyCollectionType : CollectionType {
var startIndex : MyIndex { return MyIndex(value: 0) }
var endIndex : MyIndex { return MyIndex(value: 3) }
subscript(position : MyIndex) -> String {
return "I am element #\(position.value)"
}
}
Example:
let coll = MyCollectionType()
for elem in coll {
print(elem)
}
/*
I am element #0
I am element #1
I am element #2
*/
But we can also define a forward index type without declaring
any Distance type, and using the default protocol implementations
for advancedBy() and distanceTo():
struct MyOtherIndex : ForwardIndexType {
var value : Int16
func successor() -> MyOtherIndex {
return MyOtherIndex(value: value + 1)
}
}
func ==(lhs : MyOtherIndex, rhs : MyOtherIndex) -> Bool {
return lhs.value == rhs.value
}
Now MyOtherIndex.Distance == Int because that is the default type
as defined in ForwardIndexType.
So how does this apply to your function?
You cannot assume that
Index.Distance is Int for an arbitrary collection.
You can restrict the function to collection types with
Index.Distance == Int:
func randomElement<T: CollectionType where T.Index.Distance == Int>(list: T)
But you can also utilize that _SignedIntegerType can be converted to and from IntMax:
func randomElement<T: CollectionType>(list: T) -> T.Generator.Element {
let len = UInt32(list.count.toIntMax())
let element = IntMax(arc4random_uniform(len))
return list[list.startIndex.advancedBy(T.Index.Distance(element))]
}
Note also that the return type is determined as T.Generator.Element,
and cannot be an arbitrary generic type X.
This function works with arbitrary collections, for example Array, ArraySlice, or String.CharacterView:
let array = [1, 1, 2, 3, 5, 8, 13]
let elem1 = randomElement([1, 2, 3])
let slice = array[2 ... 3]
let elem2 = randomElement(slice)
let randomChar = randomElement("abc".characters)
but also with the above custom collection type:
let mc = MyCollectionType()
let r = randomElement(mc)
In the title of your question you talk about Array. But in your code you are declaring the input param as a CollectionType.
If you really want to receive a Generic Array param then this is the code
func randomElement<T>(list: [T]) -> T {
let len = UInt32(list.count)
let random = Int(arc4random_uniform(len))
return list[random]
}
This is the simplest example what you want.
extension CollectionType where Index.Distance == Int {
func randomElement() -> Self.Generator.Element {
let randomIndex = Int(arc4random_uniform(UInt32(count)))
return self[startIndex.advancedBy(randomIndex)]
}
}

Elegant way to get the first n elements of a SequenceType

Is there an elegant way (think one-liner) to get the first n elements of a SequenceType in Swift?
I could of course write a for-loop that terminates after n elements but that's a little bulky.
Note also that the solution should be able to deal with infinite sequences.
Isn't it exactly what mySequence.prefix(numberOfElements) does?
In Swift 2, you can create this as an extension:
extension SequenceType {
func take(n: Int) -> [Generator.Element] {
var result: [Generator.Element] = []
var g = self.generate()
for _ in 1...n {
if let next = g.next() {
result.append(next)
} else {
break
}
}
return result
}
}
In Swift 1, it would have to written as a function:
func take<Seq: SequenceType>(n: Int, xs: Seq) -> [Seq.Generator.Element] {
var result: [Seq.Generator.Element] = []
var g = xs.generate()
for _ in 1...n {
if let next = g.next() {
result.append(next)
} else {
break
}
}
return result
}
Note that in either case, SequenceType does not specify what happens if you call generate() more than once. It could return the same values (as in an Array). It could return different values (as in an audio data stream). It could return nothing at all. So the caller of take() may need some special knowledge about its impact on the sequence.
SequenceType only supports generate(). Perhaps a more 'Swiftly' approach would be to define a Generator that given a start and end index and a 'base' generator would skip over the first elements, start returning some, and then stop after end index. Like this:
struct SubscriptGenerator<Base: GeneratorType> : GeneratorType {
var nowIndex : Int = 0
let endIndex : Int
let begIndex : Int
var generator : Base
init (generator: Base, startIndex: Int, endIndex: Int) {
precondition(startIndex < endIndex, "oops")
self.generator = generator
self.endIndex = endIndex
self.begIndex = startIndex
}
// MARK - GeneratorType
typealias Element = Base.Element
mutating func next() -> Element? {
while (nowIndex < begIndex) { nowIndex++; generator.next () }
return nowIndex++ < endIndex ? generator.next() : nil
}
}
This is only an example. One could define an convenience init() that takes a SequenceType and produces the base generator. In action:
75> var gen = [10,20,30,40,50].generate()
76> var sg = SubscriptGenerator(generator: gen, startIndex: 1, endIndex:3)
sg: SubscriptGenerator<IndexingGenerator<[Int]>> = { ... }
77> sg.next()
$R2: Int? = 20
78> sg.next()
$R3: Int? = 30
79> sg.next()
$R4: Int? = nil
See Swift's EnumerateGenerator for an example.
Note: it might be the Stride nexus of Swift functionality does what you want already.
Why not
var seq = NominalSequence().generate()
var a = (0..<10).map({_ in seq.next()!})
?
Two lines, but funtional-ish.