Linq喜欢函数GroupMultipleValBy

时间:2016-11-27 01:07:28

标签: linq f#

在学习F#+ Linq的真棒的过程中我遇到了一个问题,我无法解决(很好)使用函数,OOP,也没有像Linq那样的语法,有人愿意帮忙吗?

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

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

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

我需要的是这个:

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

这将改为“鲍勃已完成第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)
    }

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

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

2 个答案:

答案 0 :(得分:5)

如果你能坚持&#34;经典&#34; F#代码可以用更易读的方式重写它(特别是通过使用本地代码使代码更具可读性) 好吧Tomas似乎打败了我,我们已经和一些&#34;怪癖&#34;走了大致相同的道路。在中间

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)

要理解的难点是folder,要保持所需顺序的学期,我们要么必须添加一个额外的步骤来反转该部分,要么使用延续

使用flip添加了{以及使用@来保持免费),这让我觉得Tomas代码更好&#34; (但他的答案是学期和课程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

答案 1 :(得分:4)

如果您不坚持使用query语法(如果您正在使用数据库时需要它,但在使用内存数据时只是其中一个选项),那么我可能会使用简单的语法Seq.groupBy功能:

db 
|> Seq.groupBy (fun (name, _, _) -> name)
|> Seq.map (fun (name, group) ->
    name,
    group |> Seq.map (fun (_, sem, _) -> sem),
    group |> Seq.collect (fun (_, _, courses) -> courses) )

在这里,我们说我们想按学生姓名分组记录并返回三个:

  • 学生姓名,用作分组键
  • 获取所有记录的学期
  • 收集他们参加的所有课程

这不短于您的版本,但我认为groupBymap的组合是一种相当常见的模式,很容易理解。那就是说,我很好奇看到其他答案!我可以想象会有更好的方法来做到这一点......