Linq喜欢函数GroupMultipleValBy

arc*_*tiq 3 linq f#

在学习F#+ Linq的awesomne​​ss的过程中,我遇到了一个问题,我无法解决(很好)使用函数,OOP和Linq语法,是否有人愿意帮助?

让我们说我的输入是以下顺序:

let db = seq [ ("bob", 90, ['x';'y'])
               ("bob", 70, ['z'])
               ("frank", 20, ['b'])
               ("charlie", 10, ['c']) ]
Run Code Online (Sandbox Code Playgroud)

行可以读取例如"学生鲍勃已经注册了x,y在第90学期"

我需要的是这个:

[ ("bob",  [90; 70],  ['x'; 'y'; 'z']) 
  ("frank",    [20],  ['b'])
  ("charlie",  [10],  ['c']) ]
Run Code Online (Sandbox Code Playgroud)

这将改为"鲍勃已完成学期90,70并取x,y,z".

Linq/Relational方法通常为这些问题提供最可读的解决方案.但我能想到的最好的是:

type Student = string
type Semester = int
type Class = char

let restructure (inp:seq<Student * Semester * Class list>) = query {
        for (student, semester, classes) in inp do
        groupValBy (semester,classes) student into data 
        yield (data.Key, Seq.map fst data, Seq.collect snd data)
    }
Run Code Online (Sandbox Code Playgroud)

哪个既不可读,也不快,也不漂亮,也不惯用,并且由于F#的复杂性要求我写输入类型签名...

某些GroupMultipleValBy函数有更好的方法吗?非常感谢你!

Seh*_*cht 5

如果你能坚持使用"经典"F#代码,你可以用更易读的方式重写它(特别是使用本地代码使代码更具可读性)
好吧,看起来Tomas打败了我,我们已经走了大致相同的道路中间有些"怪癖"

let restructure inp =
  // could have been defined at a more global scope as helpers
  let fst3 (x, _, _) = x
  let flip f y x = f x y

  let folder cont (student, semester, classes) (_, semesters, allClasses) =
    cont (student, semester :: semesters, classes @ allClasses)

  let initialState = "", [], []

  inp
  |> Seq.groupBy fst3
  |> Seq.map (snd >> flip (Seq.fold folder id) initialState)
Run Code Online (Sandbox Code Playgroud)

难以理解的是folder,为了使学期保持在所需的顺序中,我们要么必须添加额外的步骤来反转该部分,要么使用延续来完成

flip添加使用的那个(以及使用它保持点免费)@使我认为Tomas代码"更好"(但他的回答使得学期和课程seq代替list)


附录

这里的Tomas代码以我发现更具可读性的方式编写(但这是一个品味问题),并且可能对操作的内容更加不可知,尽管它更长
[不需要任何东西它的答案很好]

let restructure inp =
  // could have been defined at a more global scope as helpers
  let fst3 (x, _, _) = x
  let snd3 (_, y, _) = y
  let trd3 (_, _, z) = z

  let mapping (key, values) =
    key,
    // replace with commented part to have lists instead of seqs
    values |> Seq.map snd3, //[ for value in values -> snd3 value ],
    values |> Seq.collect trd3 //[ for value in values do yield! trd3 value ]

  inp
  |> Seq.groupBy fst3
  |> Seq.map mapping
Run Code Online (Sandbox Code Playgroud)