Нарезка подобной функциональности из списка в F #
Вопрос
С массивом let foo = [|1;2;3;4|]
Я могу использовать любое из следующих действий, чтобы вернуть фрагмент массива.
foo.[..2]
foo.[1..2]
foo.[2..]
Как я могу сделать то же самое для списка let foo2 = [1;2;3;4]
?Когда я пробую тот же синтаксис, что и массив, я получаю error FS00039: The field, constructor or member 'GetSlice' is not defined.
Какой метод получения подраздела списка является предпочтительным и почему они не поддерживают GetSlice?
Решение
Каков предпочтительный метод получения подраздела списка и почему не создается для поддержки Getslice?
Давайте сделаем последний вопрос первым, а первый вопрос последним:
Почему списки не поддерживают GetSlice
Списки реализованы как связанные списки, поэтому у нас нет эффективного индексированного доступа к ним.Сравнительно говоря, foo.[|m..n|]
берет O(n-m)
время для массивов, эквивалентный синтаксис занимает O(n)
время в списках.Это довольно большая проблема, поскольку она не позволяет нам эффективно использовать синтаксис срезов в подавляющем большинстве случаев, когда он был бы полезен.
Например, мы можем разрезать массив на части одинакового размера за линейное время:
let foo = [|1 .. 100|]
let size = 4
let fuz = [|for a in 0 .. size .. 100 do yield foo.[a..a+size] |]
Но что, если вместо этого мы будем использовать список?Каждый звонок в foo.[a..a+size]
займет все больше и больше времени, вся операция O(n^2)
, что делает его совершенно непригодным для работы.
В большинстве случаев нарезка списка — неправильный подход.Обычно мы используем сопоставление с образцом для перемещения по спискам и управления ими.
Предпочитаемый метод разрезания списка?
По возможности используйте сопоставление с образцом.В противном случае вы можете вернуться к Seq.skip
и Seq.take
чтобы разрезать для вас списки и последовательности:
> [1 .. 10] |> Seq.skip 3 |> Seq.take 5 |> Seq.toList;;
val it : int list = [4; 5; 6; 7; 8]
Другие советы
F# 4.0 позволит нарезать синтаксис для списков (связь).
Обоснование здесь:
Тип списка F# уже поддерживает оператор индекса xs.[3].Это сделано несмотря на то, что списки в F# являются связанными списками — списки настолько часто используются в F#, что в F# 2.0 было решено поддержать это.
Поскольку поддерживается синтаксис индекса, имеет смысл также поддерживать синтаксис срезов F#, напримерхз.[3..5].Очень странно переключаться на тип массива, чтобы использовать срезы, но вам не обязательно делать это для индексации.
Тем не менее, ответ Джульетты о том, что в большинстве случаев нарезка списка является неправильным подходом, по-прежнему остается верным.Так что будьте мудры при использовании этой функции.