上周,我们借助数据库解决了前25个词频问题。 这周,我们将回到单独使用代码来解决它。 但是,解决方案的模型将设计为电子表格。
这是《编程风格练习》重点系列的第 15 个帖子。其他帖子包括:
- 以编程风格介绍练习
- 以编程风格进行练习,将内容堆叠起来
- 编程风格的练习,Kwisatz Haderach风格
- 编程风格的练习,递归
- 具有高阶功能的编程风格的练习
- 以编程风格进行练习
- 以编程风格进行练习,回到面向对象的编程
- 编程风格的练习:地图也是对象
- 编程风格的练习:事件驱动的编程
- 编程风格的练习和事件总线
- 反思编程风格的练习
- 面向方面的编程风格的练习
- 编程风格的练习:FP&I / O
- 关系数据库风格的练习
- 编程风格的练习:电子表格 (此职位)
- 并发编程风格的练习
- 编程风格的练习:在线程之间共享数据
- 使用Hazelcast以编程风格进行练习
- MapReduce样式的练习
- 编程风格的练习总结
电子表格模型的原理
电子表格包含许多单元格,每个单元格都具有一个值和一个公式 。 就像在常规电子表格中一样,公式是一个可以引用另一个单元格值并计算当前单元格值的函数。
以下是候选单元格的列表及其说明:
细胞 | 类型 | 式 |
---|---|---|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
下一步是将以上所有单元格放入一个集合中,并根据公式顺序设置该值。
data classCell<T,V>(varvalue:T,varformula:V) (1) (3)
typealiasSpreadsheet=List<Cell<List<Any>,()->List<Any>>> (2) (3)
valspreadsheet:Spreadsheet=
listOf(allWords,stopWords,nonStopWords,uniqueWords,counts,sortedData)
update(spreadsheet)
privatefunupdate(cells:Spreadsheet){
cells.forEach{
it.value=it.formula() (4)
}
}
- 在Kotlin中,
Pair
是不可变的,因此我们需要一个自定义类来对单元进行建模 - Kotlin的类型别名允许为具有泛型的集合命名,而无需创建完整的类型
- 单元格在Python版本中被称为“列”。 我更新了语义以更好地反映电子表格的建模:“列”变为“单元格”,“单元格集合”变为“电子表格”
- 通过调用单元格的功能来更新单元格的值
迈向不变
为了再次证明无论选择哪种编程范例都可以使用不变性(应该?),让我们迁移到递归和不变数据结构。
主要步骤是彻底更改更新功能:
privatefunupdate(cells:Spreadsheet){
cells.forEach{
it.value=it.formula() (1)
}
}
privatefunupdate(columns:Spreadsheet):Spreadsheet{ (2)
tailrecfunrecurseUpdate(todo:Spreadsheet,acc:Spreadsheet):Spreadsheet{ (3)
returnif(todo.isEmpty())acc
else{
valcolumn=todo.first()
valf=column.second
if(fis()->List<Any>) (4)
recurseUpdate(todo.takeLast(todo.size-1),acc+(f()tof)) (5)
else{
valg=fas(List<Any>)->List<Any>
recurseUpdate(todo.takeLast(todo.size-1),
acc+(g(acc.last().first)tof)) (6)
}
}
}
returnrecurseUpdate(columns,arrayListOf())
}
typealiasSpreadsheet=List<Pair<List<Any>,Function<List<Any>>>> (7)
- 可变版本:单元格的值已更改
- 不可变版本:该函数返回电子表格
- 使用尾递归以获得更好的性能
- 检查该函数是否有任何参数。
- 如果函数不接受任何参数( 例如,读取停用词),则只需调用公式并返回具有已更新单元格值的新数据结构
- 如果函数接受参数,则从最后一个单元格的值获取所需的参数。 这显然是一个巨大的约束,但在我们的情况下有效。
- 类型别名也需要更新
此时,可以更改代码以使用此新版本:
valspreadsheet:Spreadsheet=listOf(allWords,nonStopWords,counts,sortedData)
return(update(spreadsheet)
.last()
.first
.take(25)asList<Pair<String,Int>>)
.toMap()
结论
将问题建模为电子表格是一个有趣的转折。
请注意,与常规电子表格软件相反,需要显式更新值:每当从属值发生更改时,都没有实现观察者模式来更新值的实现。
我相信不可变的版本尽管管理起来有点复杂,但可以对每个功能进行更好的单元测试。
翻译自: https://blog.frankel.ch/exercises-programming-style/15/