В Haskell существует функция «взять n list», которая возвращает первые n элементов из списка. Например, «sum (take 3 xs)» суммирует первые три элемента в списке xs. Имеет ли F # эквивалент? Я ожидал, что это будет одна из функций List, но я не могу обнаружить ничего похожего.Есть ли у F # эквивалент Haskell's take?
ответ
Да, это называется Seq.take
. Использование похоже на Haskell's: Seq.take
источник подсчета.
Чтобы использовать его в списке, сначала используйте
(Update: Как видно из комментариев, это не обязательно.)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
(но это только моя догадка ...)
Nice разъяснений. – McMuttons
@McMuttons: Спасибо! Я не был уверен, должен ли я опубликовать его или нет, потому что большинство вещей уже упоминалось в комментариях. Итак, я рад, что он используется! –
Seq.take работает, как уже указывали другие, но все операции Seq в списке приходят по себестоимости. В случае Seq.take это не удивительно, поскольку список нужно скопировать.
Более примечательно, что, например, Seq.concat в списке занимает намного больше времени, чем List.concat.
Я предполагаю, что это означает, что вы не просто получаете доступ к списку как seq при вызове функции Seq.xxx, но и о том, что список скопирован/преобразован в Seq за кулисами.
редактировать: Причина, я сделал вывод, выше, была эта скамья с помощью F # интерактивными:
#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 сек. (кратчайшее время нескольких повторных тестов только для линий длины, исключая линию генерации списка).
Я не думаю, что это правильно. 'list <'t>' реализует интерфейс 'seq <'t>', поэтому нет необходимости в преобразовании и нет причин ожидать, что копия будет выполнена. Кроме того, 'Seq.take' работает лениво, тогда как' List.take' не может, поэтому в длинном списке операции последовательности почти наверняка будут быстрее, если потребуется только фронт результирующей последовательности. Однако может оказаться правдой, что реализация функции «List.take» с помощью сопоставления с образцом будет работать лучше, чем реализация «Seq.take», которая перечисляет список, если вы хотите с нетерпением получить доступ ко всем элементам результирующего списка. – kvb
Мое заключение о конверсиях, вероятно, было неправильным, но что-то происходит, и требуется дополнительное время. Я редактировал свой пост и добавил некоторые тайминги. – Batibix
- 1. Есть ли эквивалент F # Enumerable.DefaultIfEmpty?
- 2. Есть ли у ржавчины идиоматический эквивалент F # typedefs?
- 3. Есть ли F # эквивалент TPL Parallel.Invoke?
- 4. Есть ли эквивалент F # Seq.windowed в C#?
- 5. Есть ли эквивалент `tail -f` в Perl?
- 6. Есть ли эквивалент F # для обещания Скалы?
- 7. Есть ли эквивалент Haskell единиц измерения F #?
- 8. Есть ли эквивалент хвоста -f в Windows?
- 9. Есть ли у F # общая арифметическая поддержка?
- 10. Есть ли у F # оператор выхода цикла?
- 11. Есть ли у Sencha эквивалент радиостанции JQuery?
- 12. Есть ли у AngularJS эквивалент $ (document) .ajaxSuccess()?
- 13. Есть ли у JavaScript эквивалент? : оператор?
- 14. Есть ли у android эквивалент UIScrollView?
- 15. Есть ли у jquery эквивалент dojo.subscribe()?
- 16. Есть ли у python эквивалент Javascript's 'btoa'
- 17. Есть ли у StackTraceElement [] эквивалент Throwable.printStackTrace()?
- 18. У jquery есть эквивалент dojo.connect()?
- 19. У jquery есть эквивалент dojo.hitch()?
- 20. У Angular2 есть эквивалент $ document
- 21. Есть ли эквивалент F # |> (цепочка методов) в Ruby?
- 22. Есть ли однострочный эквивалент perl: sed -n -f multipatternfile textfile?
- 23. Есть ли эквивалент F # для этого метода расширения C#?
- 24. Есть ли у F # полиморфизм строк (или что-то подобное?)
- 25. У списков Python есть эквивалент dict.get?
- 26. Есть ли способ F # напечатать тип выражения?
- 27. Есть ли ⇧ есть эквивалент?
- 28. У любого языка есть эквивалент Ruby's RubySpec?
- 29. У Elm есть эквивалент «Прочитано» Haskell
- 30. Играет! У Framework есть эквивалент phpinfo?
Это похоже на то, что я ищу. Тестирование сейчас. :) – McMuttons
На самом деле, действие haskell действует как Seq.truncate, а не Seq.take. – sepp2k
Поскольку список наследуется от IEnumerable, вам не нужно сначала преобразовывать его в последовательность, чем я могу видеть. Использование Seq.take в списке отлично работало. – McMuttons