'How can I perform an Array Slice in Swift?

var mentions = ["@alex", "@jason", "@jessica", "@john"]

I want to limit my array to 3 items, so I want to splice it:

var slice = [String]()
if mentions.count > 3 {
    slice = mentions[0...3] //alex, jason, jessica
} else {
    slice = mentions
}

However, I'm getting:

Ambiguous subscript with base type '[String]' and index type 'Range'

Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31) Target: x86_64-apple-macosx10.9



Solution 1:[1]

The problem is that mentions[0...3] returns an ArraySlice<String>, not an Array<String>. Therefore you could first use the Array(_:) initialiser in order to convert the slice into an array:

let first3Elements : [String] // An Array of up to the first 3 elements.
if mentions.count >= 3 {
    first3Elements = Array(mentions[0 ..< 3])
} else {
    first3Elements = mentions
}

Or if you want to use an ArraySlice (they are useful for intermediate computations, as they present a 'view' onto the original array, but are not designed for long term storage), you could subscript mentions with the full range of indices in your else:

let slice : ArraySlice<String> // An ArraySlice of up to the first 3 elements
if mentions.count >= 3 {
    slice = mentions[0 ..< 3]
} else {
    slice = mentions[mentions.indices] // in Swift 4: slice = mentions[...]
}

Although the simplest solution by far would be just to use the prefix(_:) method, which will return an ArraySlice of the first n elements, or a slice of the entire array if n exceeds the array count:

let slice = mentions.prefix(3) // ArraySlice of up to the first 3 elements

Solution 2:[2]

We can do like this,

let arr = [10,20,30,40,50]
let slicedArray = arr[1...3]

if you want to convert sliced array to normal array,

let arrayOfInts = Array(slicedArray)

Solution 3:[3]

You can try .prefix(). Returns a subsequence, up to the specified maximum length, containing the initial elements of the collection. If the maximum length exceeds the number of elements in the collection, the result contains all the elements in the collection.

let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(2))    // Prints "[1, 2]"
print(numbers.prefix(10))   // Prints "[1, 2, 3, 4, 5]"

Solution 4:[4]

Can also look at dropLast() function:

var mentions:[String] = ["@alex", "@jason", "@jessica", "@john"]
var slice:[String] = mentions    
if mentions.count > 3 {
   slice = Array(mentions.dropLast(mentions.count - 3))
}
//print(slice) => ["@alex", "@jason", "@jessica"]

Solution 5:[5]

General solution:

extension Array {
   func slice(size: Int) -> [[Element]] {
      (0...(count / size)).map{Array(self[($0 * size)..<(Swift.min($0 * size + size, count))])}
   }
}

Solution 6:[6]

I came up with this:

public extension Array {
    func slice(count: Int) -> [some Collection] {
        let n = self.count / count  // quotient
        let i = n * count           // index
        let r = self.count % count  // remainder
        let slices = (0..<n).map { $0 * count }.map { self[$0 ..< $0 + count] }
        return (r > 0) ? slices + [self[i..<i + r]] : slices
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Ilya Valito
Solution 4
Solution 5 Björn B.
Solution 6 Kaz Yoshikawa