Быстрый ленивый индекс игнорирует фильтр - PullRequest
0 голосов
/ 21 января 2019

Как работает подписка на ленивый фильтр?

let ary = [0,1,2,3]
let empty = ary.lazy.filter { $0 > 4 }.map { $0 + 1 }
print(Array(empty)) // []
print(empty[2])     // 3

Похоже, он просто игнорирует фильтр и в любом случае делает карту. Это где-то задокументировано? Какие еще ленивые коллекции имеют такое исключительное поведение?

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Чтобы добавить ответ Carpsen90, вы сталкиваетесь с одной из особенностей Collection: не рекомендуется и небезопасно получать доступ к коллекциям по абсолютному индексу, даже если система типов позволяет это.Поскольку полученная коллекция может быть подмножеством другой.

Давайте рассмотрим более простой пример - нарезку массива:

let array = [0, 1, 2, 3, 4]
let slice = array[2..<3]
print(slice) // [2]
print(slice.first) // Optional(2)
print(slice[0]) // crashes with array index out of bounds

Даже если slice - это коллекция, индексируемая целым числом,все еще небезопасно использовать абсолютные целые числа для доступа к элементам этой коллекции, поскольку коллекция может иметь другой набор индексов.

0 голосов
/ 21 января 2019

Все сводится к подписке LazyFilterCollection с целым числом, которое в этом случае игнорирует предикат и перенаправляет операцию индексации на базу.

Например, если мы ищем строго положительные целые числа в массиве:

let array = [-10, 10, 20, 30]
let lazyFilter = array.lazy.filter { $0 > 0 }

print(lazyFilter[3])                 // 30

Или, если мы ищем строчные символы в строке:

let str = "Hello"
let lazyFilter = str.lazy.filter { $0 > "Z" }

print(lazyFilter[str.startIndex])    //H

В обоих случаях нижний индекс перенаправляется в базовую коллекцию.

Правильный способ подписки LazyFilterCollection - это использование LazyFilterCollection<Base>.Index, как описано в документации :

let start = lazyFilter.startIndex
let index = lazyFilter.index(start, offsetBy: 1)
print(lazyFilter[index])  

Что дает 20 для примера массива или l для примера строки.


В вашем случае попытка получить доступ к индексу 3:

let start = empty.startIndex
let index = empty.index(start, offsetBy: 3)
print(empty)

вызовет ожидаемую ошибку времени выполнения:

Неустранимая ошибка: индекс выходит за пределы диапазона

...