在学习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函数有更好的方法吗? 非常感谢你!
答案 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) )
在这里,我们说我们想按学生姓名分组记录并返回三个:
这不短于您的版本,但我认为groupBy
和map
的组合是一种相当常见的模式,很容易理解。那就是说,我很好奇看到其他答案!我可以想象会有更好的方法来做到这一点......