类Linq函数组multiplevalby
在学习F#+Linq的过程中,我遇到了一个我无法(很好地)用函数式、OOP或类似Linq的语法解决的问题,有人愿意帮忙吗 假设我的输入是以下顺序:类Linq函数组multiplevalby,linq,f#,Linq,F#,在学习F#+Linq的过程中,我遇到了一个我无法(很好地)用函数式、OOP或类似Linq的语法解决的问题,有人愿意帮忙吗 假设我的输入是以下顺序: let db=seq[(“bob”,90,['x';'y'])) (“鲍勃,70,['z'])) (“弗兰克,20,['b'])) (“查理”,10,['c'])] 行可以读取例如“学生bob在90学期已在x,y注册” 我需要的是: [(“bob”、[90;70]、“x”;“y”;“z”]) (“弗兰克”[20],“b”]) (“查理”[10],[
let db=seq[(“bob”,90,['x';'y']))
(“鲍勃,70,['z']))
(“弗兰克,20,['b']))
(“查理”,10,['c'])]
行可以读取例如“学生bob在90学期已在x,y注册”
我需要的是:
[(“bob”、[90;70]、“x”;“y”;“z”])
(“弗兰克”[20],“b”])
(“查理”[10],[c]])]
这将改为“Bob已完成90、70学期,并参加了x、y、z考试”
Linq/关系方法通常为此类问题提供最具可读性的解决方案。但我能想到的最好办法是:
type Student=string
类型=int
类型Class=char
让重组(inp:seq)=查询{
inp do的(学生、学期、班级)
groupValBy(学期、班级)学生输入数据
收益率(data.Key、Seq.map fst数据、Seq.collect snd数据)
}
它既不可读,也不快速,也不美观,也不惯用,而且由于F#的复杂性,需要我编写输入类型签名
有没有更好的方法来实现GroupMultipleValBy函数?
多谢各位 如果您不坚持使用
查询
语法(这是处理数据库时需要的,但只是处理内存数据时的选项之一),那么我可能会使用简单的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
的组合是一种相当常见的模式,非常容易理解。也就是说,我很想看到其他答案!我可以想象会有一种更好的方法来做到这一点……如果你能坚持使用“经典”F#代码,你可以用更可读的方式重写它(特别是通过使用局部变量使代码更可读)这似乎比我强,我们走的路大致相同,中间有一些“怪癖” 很难理解的部分是
文件夹
一个,为了使学期保持在想要的顺序,我们必须添加一个额外的步骤来反转该部分,或者像这里一样使用延续
加上@
的使用(以及使用flip
来保持它的自由)使我认为托马斯的代码“更好”(但他的答案使学期和班级顺序而不是列表)
附录
以下是Tomas的代码,我发现它更具可读性(但这是一个品味问题),而且可能对正在被操纵的内容更不可知,尽管它更长
[这并不意味着它的答案很好]
你修改过的Petriceks解决方案更具可读性,我不知道它是否足以作为正确答案。虽然第一个代码片段似乎不必要地抽象和复杂。虽然您可以为fst3
、snd3
和trd3
定义助手以避免显式函数,但我认为这失去了原始代码在命名事物时的一些意义(学期
和课程
)因此,你可以阅读它,了解你正在处理的事情……实际上,我可能会避免使用三元素元组,而是使用记录。然后你会使用记录属性,这要求你清楚你在使用什么-我喜欢使用列表理解的想法-然后你会得到:[for v in group->v.term]
和[for v in group do yield!v.Courses]
使用命名参数更清晰。但当我在其他地方使用查询时,我将继续查找。我相信查询通常提供一个如此原始的解决方案,即使是非FSharper也能理解。这是一个很大的优点。我是否过早地选择了答案?@arctiq我相信您可以更改选择的答案-如果您发现其他答案更有用,您完全可以随意更改!
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)
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