Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
类Linq函数组multiplevalby_Linq_F# - Fatal编程技术网

类Linq函数组multiplevalby

类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],[

在学习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],[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