F # - сортировка последовательности с использованием порядковых рангов - PullRequest
1 голос
/ 09 октября 2019

У меня есть последовательность, сгенерированная CsvProvider:

RD;RT;RC;RDT;RG;H;HA;HS;RSP;RFP;RCT;RPZ;HR;HT;RCID
Schema="String,String,String,String,String,String,int,String,String,String,int,String,int,String,String"

, которая может содержать равные ранги в позиции "e: int".

module SOQN =

   open System

   let ordinalRanks input =
      input
      // |> Seq.sortBy (fun (_, _, _, _, e, _) -> e)
      |> Seq.groupBy (fun (a, b, c, _, e, _) -> (a, b, c, e))
      |> Seq.mapi (fun i a b c d e f -> (a, b, c, d, i + 1, f))

   [<EntryPoint>]
   let main() = 
      let input = seq [ (2107, "HVST", "1315", "Alpha", 1, "JS");
                        (2107, "HVST", "1315", "Beta", 2, "ASC");
                        (2107, "HVST", "1315", "Gamma", 2, "ASC");...
                        (2237, "ABCD", "0905", "Pi", 1, "ABC");
                        (2237, "ABCD", "0905", "Sigma", 1, "CDE");
                        (2237, "ABCD", "0905", "Delta", 2, "EFG");...
                      ]

      let output = ordinalRanks input
      printfn "%A" output

// Actual Output
// seq [ (2107, "HVST", "13-15", "Alpha", 1, "JS");
//       (2107, "HVST", "13-15", "Beta", 2, "ASC");
//       (2107, "HVST", "13-15", "Gamma", 2, "ASC");...] 
//       (2237, "ABCD", "0905", "Pi", 1, "ABC");
//       (2237, "ABCD", "0905", "Sigma", 1, "CDE");
//       (2237, "ABCD", "0905", "Delta", 2, "EFG");...

// Expected Output
// seq [ (2107, "HVST", "13-15", "Alpha", 1, "JS");
//       (2107, "HVST", "13-15", "Beta", 2, "ASC");
//       (2107, "HVST", "13-15", "Gamma", 3, "ASC");...]
//       (2237, "ABCD", "0905", "Pi", 1, "ABC");
//       (2237, "ABCD", "0905", "Sigma", 2, "CDE");
//       (2237, "ABCD", "0905", "Delta", 3, "EFG");...
//

Как сортировать, используя Порядковые ранги . Обратите внимание, что рейтинги находятся в группах, определяемых первыми тремя позициями. Посоветуйте пожалуйста?

// RD;RT;RC;RDT;RG;H;HA;HS;RSP;RFP;RCT;RPZ;HR;HT;RCID
let sortedData (inputCsv: String) = 
    let csvInput = Sample2Sort.Load(inputCsv)
    let csvHeaders = [| sprintf "%s" ((csvInput.Headers.Value) |> String.concat ";") |]
    let csvOutput = 
        csvInput.Rows
        |> Seq.filter (fun row -> row.RFP > 0)
        |> Seq.sortBy (fun row -> (DateTime.Parse(row.RD)), row.RC, row.RT, row.RFP)
        // |> Seq.groupBy (fun (a, b, c, _, _, _) -> (a, b, c))
        |> Seq.groupBy (fun (a, b, c, _, _, _) -> (row.RD, row.RC, row.RT))
        // |> Seq.collect (fun (_, group) -> group |> Seq.mapi (fun i (a, b, c, d, _, f) -> a, b, c, d, i + 1, f))
        |> Seq.collect (fun (_, group) -> 
            group |> Seq.mapi (fun i (a, b, c, d, _, f) -> 
                row.RCID, row.RC, ((row.RD, " ", row.RT) |> String.Concat)), row.RH, i + 1, row.HT)
    (csvHeaders, csvOutput)

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Я думаю, что основная проблема вашего подхода заключается в том, что вы неправильно обрабатываете тот факт, что groupBy превращает последовательность значений в последовательность последовательностей значений - она ​​возвращает список групп, где каждая группа содержит все элементыв группе.

Ваше первое использование groupBy правильно, но я считаю, что вам нужно использовать только a, b, c в качестве ключа группировки. После группировки вы можете использовать collect, чтобы получить плоский список результатов. Вам нужно переместить вызов функции mapi внутри лямбды и запустить его на всех элементах группы:

let ordinalRanks input =
  input
  |> Seq.groupBy (fun (a, b, c, _, _, _) -> (a, b, c))
  |> Seq.collect (fun (_, group) ->
    group |> Seq.mapi (fun i (a, b, c, d, _, f) ->
        a, b, c, d, i + 1, f))

Я не совсем уверен, как вы хотите использовать существующий порядок e. Этот фрагмент просто игнорирует его, но он дает правильный результат для вашего образца ввода.

0 голосов
/ 10 октября 2019

Томас, я смог решить мою реальную проблему, основываясь на твоем решении моей проблемы с игрушкой выше.

// RD;RT;RC;RDT;RG;H;HA;HS;RSP;RFP;RCT;RPZ;HR;HT;RCID
let sortedData inputCsv = 
    let csvInput = Sample.Load(inputCsv)
    let csvHeaders = [| sprintf "%s" ((csvInput.Headers.Value) |> String.concat ";") |]
    let csvOutput = 
        csvInput.Rows
        |> Seq.filter (fun row -> row.RFP > 0)
        |> Seq.sortBy (fun row -> (DateTime.Parse(row.RD)), row.RC, row.RT, row.RFP)
        |> Seq.groupBy (fun row -> (row.RD, row.RC, row.RT))
        |> Seq.collect (fun (_, group) -> 
            group |> Seq.mapi (fun i row -> 
                               row.RCID, row.RC, 
                               ((row.RD, " ", row.RT) |> String.Concat)), 
                               row.RH, i + 1, row.HT)
    (csvHeaders, csvOutput)

Еще раз спасибо за твое терпение и пользу твоего опыта.

...