В Swift, какой самый чистый способ получить последние два элемента в массиве?

Есть ли более чистый способ получить последние два элемента массива в Swift? В общем, я стараюсь избегать такого подхода, так как так легко быть по-одному с индексами. (С помощью Swift 1.2 для этого примера.)

// Swift -- slices are kind of a hassle?
let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]

func getLastTwo(array: [String]) -> [String] {
    if array.count <= 1 {
        return array
    } else {
        let slice: ArraySlice<String> = array[array.endIndex-2..<array.endIndex]
        var lastTwo: Array<String> = Array(slice)
        return lastTwo
    }
}

getLastTwo(oneArray)   // ["uno"]
getLastTwo(twoArray)   // ["uno", "dos"]
getLastTwo(threeArray) // ["dos", "tres"]

Я надеялся на что-то более близкое к удобству Python.

## Python -- very convenient slices
myList = ["uno", "dos", "tres"]
print myList[-2:] # ["dos", "tres"]

Ответы

Ответ 1

myList[-2:]

Да, у меня есть запрос на повышение, который запрашивает отрицательную индексную нотацию, и я предлагаю вам также создать файл.

Однако вы не должны делать это более сложным для себя, чем вам нужно. Встроенная глобальная функция suffix выполняет именно то, что вам нужно:

let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]

let arr1 = suffix(oneArray,2) // ["uno"]
let arr2 = suffix(twoArray,2) // ["uno", "dos"]
let arr3 = suffix(threeArray,2) // ["dos", "tres"]

Результат - это фрагмент, но вы можете принудить его к массиву, если вам нужно.

Ответ 2

В Swift 5, в соответствии с вашими потребностями, вы можете выбрать один из следующих шаблонов, чтобы получить новый массив из двух последних элементов массива.


# 1. Использование suffix(_:) Array suffix(_:)

В Swift объекты, соответствующие протоколу Collection, имеют метод suffix(_:). suffix(_:) массива suffix(_:) имеет следующее объявление:

func suffix(_ maxLength: Int) -> ArraySlice<Element>

Возвращает подпоследовательность, вплоть до заданной максимальной длины, содержащую последние элементы коллекции.

Использование:

let array = [1, 2, 3, 4]
let arraySlice = array.suffix(2)
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]

# 2. Использование subscript(_:) Array subscript(_:)

В качестве альтернативы методу suffix(_:) вы можете использовать subscript(_:) Array subscript(_:):

let array = [1, 2, 3, 4]
let range = array.index(array.endIndex, offsetBy: -2) ..< array.endIndex
//let range = array.index(array.endIndex, offsetBy: -2)... // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]

Ответ 3

В Swift 2 вы можете расширить CollectionType. Вот пример (заимствование от Роба Напира):

extension CollectionType {
    func last(count:Int) -> [Self.Generator.Element] {
        let selfCount = self.count as! Int
        if selfCount <= count - 1 {
            return Array(self)
        } else {
            return Array(self.reverse()[0...count - 1].reverse())
        }
    }
}

Вы можете использовать его на любом CollectionType. Здесь Array:

let array = ["uno", "dos", "tres"]
print(array.last(2)) // [dos, tres]

Здесь CharacterView:

let string = "looking"
print(string.characters.last(4)) // [k, i, n, g]

(Обратите внимание, что мой пример возвращает Array во всех случаях, а не в исходный тип коллекции.)

Ответ 4

Более общий ответ...

let a1 = [1,2,3,4,5]
let a2 = ["1","2","3","4","5"]

func getLast<T>(array: [T], count: Int) -> [T] {
  if count >= array.count {
    return array
  }
  let first = array.count - count
  return Array(array[first..<first+count])
}

getLast(a1, count: 2) // [4, 5]
getLast(a2, count: 3) // ["3", "4", "5"]

Ответ 5

Вы можете сохранить явную проверку для подсчета массива с помощью трехпараметрической формы advance():

func getLast<T>(array: [T], count : Int) -> [T] {
    let to = array.endIndex
    // Decrease end index by `count`, but not beyond the start index:
    let from = advance(to, -count, array.startIndex) 
    return Array(array[from ..< to])
}

getLast(oneArray, 2)   // ["uno"]
getLast(twoArray, 2)   // ["uno", "dos"]
getLast(threeArray, 2) // ["dos", "tres"]
getLast(threeArray, 4) // ["uno", "dos", "tres"]

Ответ 6

последние два элемента массива в Swift

EDIT: сначала проверяет, что myArray.count >= 2

let myArray2:Array? = myArray.count >= 2 ? [myArray[myArray.count-2], myArray[myArray.count-1]] : nil

Здесь он завернут в функцию, которая принимает массив и возвращает массив, содержащий последние два, или возвращает nil, если переданный массив не содержит по крайней мере двух элементов.

func getLastTwo(myArray:[String]) -> [String]? {
        return myArray.count >= 2 ? [myArray[myArray.count-2], myArray[myArray.count-1]] : nil
    }

Ответ 7

let items = [0, 2, 5, 3, 7, 6, 9, 10]
let count = items.count
let last2 = items[count - 2 ..< count] // [9, 10]

Ответ 8

Я сомневаюсь, что это сделает вас намного счастливее, но математика, безусловно, проще:

func getLastTwo(array: [String]) -> [String] {
    if array.count <= 1 {
        return array
    } else {
        return array.reverse()[0...1].reverse()
    }
}

Обратите внимание, что reverse() ленив, поэтому это не особенно дорого.

Ответ 9

в swift 5 вы можете использовать суффикс для получения объектов из последнего и префикс для получения объектов из первого, вот пример:

let exampleArray = ["first text", "second text", "third text"]

let arr1 = exampleArray.suffix(2) // ["second text", "third text"]
let arr2 = exampleArray.prefix(2) // ["first text", "second text"]

Результатом является срез, но вы можете привести его к массиву, если вам нужно.

Ответ 10

Решение Swift4:

let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]

let arr1 = threeArray.suffix(from: threeArray.count-2) // ["dos", "tres"]

Другие примеры, поясняющие функциональность встроенной функции Swift - func suffix(from start: Int) → ArraySlice<Element>:

let arr2 = oneArray.suffix(from: 0) // ["uno"]
let arr3 = twoArray.suffix(from: 0) // ["uno", "dos"]
let arr4 = twoArray.suffix(from: 1) // ["dos"]
let arr5 = threeArray.suffix(from: 1) // ["dos", "tres"]
let arr6 = threeArray.suffix(from: 2) // ["tres"]