Доступ к элементам в IEnumerable в F # - PullRequest
3 голосов
/ 18 мая 2011

Я пытаюсь использовать Youtube .Net API в F #, и я столкнулся с проблемой, пытаясь получить доступ к IEnumerable, возвращенному свойству userPlaylists.Entries. Ниже приведен код на c #, который я тестировал, однако я не могу вернуть отдельные элементы из коллекции IEnumerable в f #.

 Feed<Playlist> userPlaylists = request.GetPlaylistsFeed("username");
 var p = userPlaylists.Entries.Single<Playlist>(x => x.Title == "playlistname");

Записи разрешаются к типу IEnumerable<Playlist> Feed<PlayList>.Entries

IEnumerable представляется как последовательность в F #, но я не могу понять, как вернуть и отдельный элемент правильного типа, ближайший, который я получил:

let UserPlaylists = Request.GetPlaylistsFeed("username")
let pl = UserPlaylists.Entries |>
Seq.tryPick(fun x -> if x.Title="playlistname" then Some(x) else None)

Однако, кажется, это возвращает тип «Playlist option» вместо «Playlist». Кто-нибудь может предложить правильный способ получения отдельного элемента из IEnumerable?

Ответы [ 3 ]

2 голосов
/ 18 мая 2011

Метод расширения Single () выдает исключение, если не находит соответствия, и также выдает исключение, если находит более одного совпадения.В модуле F # Seq прямого эквивалента нет.Ближайшим будет Seq.find, который, например, .Single(), выдаст исключение, если не найдет совпадение, однако, в отличие от .Single(), он перестанет искать, как только найдет совпадение, и не выдаст ошибку, если большесуществует более одного совпадения.

Если вам действительно нужно поведение «выбросить ошибку, если более одного совпадения», то проще всего будет использовать этот точный метод из F #:

open System.Linq

let p = userPlaylists.Entries.Single(fun x -> x.Title = "playlistname")

Если вам не нужно поведение «бросить, если более одного совпадения», то вам не следует использовать .Single() в вашем коде на C # - .First() будет работать лучше, потому что он перестает смотреть, как только находитсовпадение.

Если бы это был я, я бы использовал краткость Seq.tryFind over Seq.tryPick и обрабатывал бы случай "not found", а не выдавал ошибку.

let userPlaylists = request.GetPlaylistsFeed("username")
let p = userPlaylists.Entries |> Seq.tryFind (fun x -> x.Title = "playlistname")
match p with
| Some pl ->
    // do something with the list
| None ->
    // do something else because we didn't find the list

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

request.GetPlaylistsFeed("username").Entries
|> Seq.tryFind (fun x -> x.Title = "playlistname")
|> function
   | Some pl ->
       // do something with the list
   | None ->
       // do something else because we didn't find the list

Мне действительно нравится оператор конвейера ...

2 голосов
/ 18 мая 2011

Seq.tryPick сродни IEnumerable.FirstOrDefault, за которым следует преобразование типа, которое не имеет семантики, которую вы ищете.Seq.pick сродни IEnumerable.First, за которым следует преобразование типа, которое является шагом в правильном направлении (при условии, что вы хотите, чтобы исключение возникало при невозможности найти какой-либо соответствующий элемент, как в IEnumerable.Single), но поскольку вам на самом деле не нужно преобразование типов, я думаю, что вы действительно хотите Seq.find, что семантически идентично IEnumerable.First:

let UserPlaylists = Request.GetPlaylistsFeed "username"
let pl = UserPlaylists.Entries |> Seq.find (fun x -> x.Title = "playlistname")

Тем не менее, если вам действительно нужна семантика IEnumerable.Single, а не IEnumerable.First, проигнорируйте это и посмотрите ответ @ JoelMueller.

1 голос
/ 18 мая 2011

Используйте метод Option.get, чтобы получить значение из опции

Seq.tryPick(fun x -> if x.Title="playlistname" then Some(x) else None)
|> Option.get

Хотя в F # я считаю более идиоматичным явно обрабатывать пустой регистр вместо использования распространения исключений

let value = Seq.tryPick(fun x -> if x.Title="playlistname" then Some(x) else None)
match value with
| None ->
  // No matching elements.  Take corrective action
| Some value ->
  // The value i'm looking for
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...