Ответ 1
Да, он называется Seq.take
. Использование кажется идентичным источнику подсчета Haskell: Seq.take
. Чтобы использовать его в списке, сначала используйте (Обновление: по-видимому, из комментариев это isn ' t необходимо.)List.toSeq
.
В Haskell существует функция "take n list", которая возвращает первые n элементов из списка. Например, "sum (take 3 xs)" суммирует первые три элемента в списке xs. Имеет ли F # эквивалент? Я ожидал, что это будет одна из функций List, но я не могу обнаружить ничего похожего.
Да, он называется Seq.take
. Использование кажется идентичным источнику подсчета Haskell: Seq.take
. Чтобы использовать его в списке, сначала используйте (Обновление: по-видимому, из комментариев это isn ' t необходимо.)List.toSeq
.
Чтобы прояснить некоторые вещи, разница между Seq.take
и Seq.truncate
(как указано в @sepp2k) заключается в том, что вторая даст вам последовательность, которая возвращает не более того количество элементов, которые вы указали (но если длина последовательности меньше, это даст вам меньше элементов).
Последовательная сгенерированная функция Seq.take
генерирует исключение, если вы пытаетесь получить доступ к элементу за пределами длины исходного списка (обратите внимание, что функция Seq.take
не генерирует исключение немедленно, потому что результат лениво сгенерирован последовательность).
Кроме того, вам не нужно явно преобразовывать список в последовательность. Под обложкой list<'a>
является .NET-классом, который наследует от типа seq<'a>
, который является интерфейсом. Тип seq<'a>
на самом деле является просто псевдонимом типа для IEnumerable<'a>
, поэтому он реализуется всеми другими коллекциями (включая массивы, изменяемые списки и т.д.). Следующий код будет работать нормально:
let list = [ 1 .. 10 ]
let res = list |> Seq.take 5
Однако, если вы хотите получить результат типа list<int>
, вам нужно будет преобразовать последовательность в список (потому что список более конкретный, чем последовательность):
let resList = res |> List.ofSeq
Я не уверен, почему библиотеки F # не предоставляют List.take
или List.truncate
. Я предполагаю, что цель заключалась в том, чтобы избежать переопределения всего набора функций для всех типов коллекций, поэтому те, где реализация последовательностей достаточно хороша при работе с более конкретным типом коллекции, доступны только в модуле Seq
(но это только моя догадка...)
Seq.take работает, как уже отмечали другие, но все операции Seq в списке приводятся по стоимости. В случае Seq.take это неудивительно, так как список должен быть скопирован.
Более примечательно, что, например, Seq.concat в списке занимает намного больше времени, чем List.concat. Я предполагаю, что это означает, что вы не просто получаете доступ к списку как seq при вызове функции Seq.xxx, но и о том, что список также скопирован/преобразован в Seq за кадром.
edit: Причина, по которой я сделал вывод выше, был на этой скамье, используя F # interactive:
#time "on";;
let lists = [for i in 0..5000000 -> [i..i+1]];;
Seq.length (Seq.concat lists);;
List.length (List.concat lists);;
На моей машине версия List.length
занимает около 1,9 с, тогда как версия Seq.length
занимает около 3,8 с (кратчайшее время нескольких повторных тестов только длины линий, исключая линию генерации списка).