Попытка создать функцию, а затем отфильтровать последовательность по «не той функции» в F # - PullRequest
0 голосов
/ 09 июня 2018

Мои данные являются ПОСЛЕДОВАТЕЛЬНОСТЬЮ:

[(40,"TX");(48,"MO");(15,"TX");(78,"TN");(41,"VT")]

Мой код выглядит следующим образом:

type Csvfile = CsvProvider<somefile>
let data = Csvfile.GetSample().Rows

let nullid row = 
    row.Id = 15

let otherid row =
    row.Id= 40

let iddata = 
   data
   |> Seq.filter (not nullid)
   |> Seq.filter (not otherid)

Я создаю функции.

Затем я хочу вызвать «не» этих функций, чтобы отфильтровать их из последовательности.

Но проблема в том, что я получаю ошибки для «row.Id» в первых двух функциях, потому что выможет сделать это только с типом.

Как мне решить эту проблему, чтобы я мог успешно ее решить.

Мой результат должен быть ПОСЛЕДОВАТЕЛЬНОСТЬЮ:

[(48,"MO);(78,"TN");(41,"VT")]

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

Пожалуйста, посмотрите ниже, как MCVE может выглядеть в вашем случае, для fsx-файла вы можете ссылаться на Fsharp.Data dll с #r, для скомпилированного проекта просто ссылаться на dll и открывать его.

#if INTERACTIVE
#r @"..\..\SO2018\packages\FSharp.Data\lib\net45\FSharp.Data.dll"
#endif

open FSharp.Data

[<Literal>]
let datafile = @"C:\tmp\data.csv"
type CsvFile = CsvProvider<datafile>
let data = CsvFile.GetSample().Rows

В конце концов, это то, чего вы хотите достичь:

data
|> Seq.filter (fun x -> x.Id <> 15)
|> Seq.filter (fun x -> x.Id <> 40)
//val it : seq<CsvProvider<...>.Row> = seq [(48, "MO"); (78, "TN"); (41, "VT")]

Один из способов сделать это - SRTP , так как они позволяютделать структурную типизацию, где тип зависит от его формы, например, в этом случае, имеющей свойство Id.Если вы хотите, вы можете определить вспомогательную функцию для двух чисел 15 и 40 и использовать ее в своем фильтре, как во втором примере.Однако синтаксис SRTP немного странный, и он разработан для случая использования, когда вам нужно применить функцию к различным типам, которые имеют некоторое сходство (в основном, как интерфейсы).

let inline getId row =
    (^T : (member Id :  int) row)

data
|> Seq.filter (fun x -> (getId x <> 15 ))
|> Seq.filter (fun x -> (getId x <> 40))
//val it : seq<CsvProvider<...>.Row> = seq [(48, "MO"); (78, "TN"); (41, "VT")]

Теперь вернемся к исходному сообщению, как вы правильно указали, ваша функция будет отображать ошибку, поскольку вы определяете ее как универсальную, но она должна работать с конкретным типом строки Csv (которая имеет свойство Id).Это очень легко исправить, просто добавьте аннотацию типа к параметру row.В этом случае ваш тип CsvFile.Row, и, поскольку CsvFile.Row имеет свойство Id, мы можем получить к нему доступ в функции.Теперь эта функция возвращает логическое значение.Вы также можете сделать так, чтобы он возвращал фактическую строку.

let nullid (row: CsvFile.Row)  =
    row.Id = 15


let otherid (row: CsvFile.Row) =
    row.Id = 40

Тогда осталось применить это внутри Seq.filter и отрицать его:

let iddata = 
    data 
    |> Seq.filter (not << nullid) 
    |> Seq.filter (not << otherid)
    |> Seq.toList
//val iddata : CsvProvider<...>.Row list = [(48, "MO"); (78, "TN"); (41, "VT")]
0 голосов
/ 09 июня 2018

Вы можете использовать оператор >> для составления двух функций:

let iddata = 
   data
   |> Seq.filter (nullid >> not)
   |> Seq.filter  (othered >> not)

См. Композиция функций и конвейерная обработка .

Или вы можете сделать это более явным:

let iddata = 
   data
   |> Seq.filter (fun x -> not (nullid x))
   |> Seq.filter  (fun x -> not (othered x))

Вы можете видеть это в действии:

let input = [|1;2;3;4;5;6;7;8;9;10|];;
let is3 value =
    value = 3;;

input |> Seq.filter (fun x -> not (is3 x));;
input |> Seq.filter (not >> is3);;

Они оба печатают val it : seq<int> = seq [1; 2; 4; 5; ...]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...