package com.datacrafts.digitalevers.curry
import java.io.{BufferedReader, Closeable, File, FileReader}
import com.esotericsoftware.minlog.Log
/**
* 这段代码使用函数柯里化的功能实现了读取文件源并将其转为List数据
* 函数柯里化的精髓是使得函数实现在依赖其他函数的情况下实现可插拔,从而在函数与函数之间的调用上进行解耦
* 比如这段代码可以在getLines底层函数上只保留 filename 一个参数,在函数体内直接调用 isReadable 和 closeStream方法来进行
* 周边逻辑的实现,一样可以达到效果,但是如果将来需要修改 isReadable 和 closeStream 的功能,不得不修改这两个方法的源代码
* 如果采用柯里化的形式 可以重新编写一个 isReadable 和 closeStream 的实现,在上层调用的时候直接将新函数作为参数传入即可
* 从而符合ocp原则。
*/
object FileReader {
/**
* 柯里化后的函数
* @param filename
* @param isFileReadable
* @param closableStream
* @return
*/
def getLines (filename: String) (isFileReadable: (File) => Boolean) (closableStream: (Closeable) => Unit): String = {
val file = new File(filename)
if (isFileReadable (file) ) {
val readerStream = new FileReader(file)
val buffer = new BufferedReader(readerStream)
try {
var content = ""
var str = ""
var isReadOver = false
while (! isReadOver) {
str = buffer.readLine ()
if (str == null) {
isReadOver = true
} else {
content += str
}
}
content
} finally {
closableStream (buffer)
closableStream (readerStream)
}
} else {
""
}
}
/**
* 判断文件是否可读
* @param file
* @return
*/
def isReadable (file: File) = {
if (null != file && file.exists() && file.canRead() ) {
true
} else {
false
}
}
/**
*关闭打开的文件流
* @param stream
*/
def closeStream (stream: Closeable) {
if (null != stream) {
try {
stream.close
} catch {
case ex:Throwable => Log.error( "[" +this.getClass.getName + ".closeStream] ", ex.getMessage)
}
}
}
}
package com.datacrafts.digitalevers.sparseMatrix
import java.io.FileWriter
import com.datacrafts.digitalevers.curry.FileReader.{closeStream, getLines, isReadable}
import com.google.gson.Gson
import scala.collection.mutable.ArrayBuffer
/**
* 此例程提供Scala对稀疏矩阵进行压缩解压模拟的操作方法
* 通用方式
*/
object normal{
implicit val filePath = ""
def main(args: Array[String]): Unit = {
/*var test = Array.ofDim[Int](11,3)
test(5)(2) = 11
test(3)(1) = 5
var resJson = zipMatrix(test)(checkMatrix)("json.txt")*/
val arr = unzipMatrix("json.txt")
}
/**
* 压缩稀疏矩阵并将其保存到文件中
*/
def zipMatrix(inArray:Array[Array[Int]])(check:(Array[Array[Int]])=>Array[Int])(implicit filePath:String) = {
val newMatrix = ArrayBuffer[Array[Int]]()
val res:Array[Int] = check(inArray)
newMatrix.append(Array(res(0),res(1),0))
for(i <- 0 until inArray.length){
for(j <- 0 until inArray(i).length){
if(inArray(i)(j) != 0){
newMatrix.append(Array(i,j,inArray(i)(j)))
}
}
}
//print(filePath)
val arr = newMatrix.toArray //ArrayBuffer -> Array -> json
val gson = new Gson()
val json = gson.toJson(arr)
if(filePath.isEmpty == true){
json
} else {
save2File(filePath,json)
}
}
/**
* 从文件中读取数据并解压成稀疏矩阵
*/
def unzipMatrix(filePath:String) = {
val content = getLines(filePath) (isReadable) (closeStream)
if(content == ""){
throw new Exception("文件内容为空")
}
val res = ArrayBuffer[Array[Int]]()
val gson = new Gson()
val arr = gson.fromJson(content,classOf[Array[Array[Int]]])
for(i <- 0 until arr.length){
if(i == 0){
for(j <- 0 until arr(i)(0)){
res.append(Array.ofDim[Int](arr(i)(1)))
}
} else {
res(arr(i)(0))(arr(i)(1)) = arr(i)(2)
}
}
res.toArray
}
/**
* 检测数组的容积(长和宽)
* @param inArray
* @return
*/
def checkMatrix(inArray:Array[Array[Int]]):Array[Int] = {
if(inArray.length > 0){
val i = inArray.length
val j = inArray(0).length
Array(i,j)
} else {
Array(0,0)
}
}
/**
* 保存字符串到文件中
* @param filePath 文件路径
* @param content 需要保存的字符内容
* @return 保证成功 true 保存失败 false
*/
def save2File(filePath:String,content:String): Boolean = {
try {
val out = new FileWriter(filePath, true)
out.write(content)
out.close()
true
} catch {
case ex: Throwable => {
false
}
}
}
////////////////
}
下面是泛型方式,在开发泛型方式的时候有一个小插曲
最开始使用Play Framework框架中的json解析库(play.api.libs.json)无法解析泛型的数组结构,更换到gson解析库,便可正常解析
package com.datacrafts.digitalevers.sparseMatrix
import com.datacrafts.digitalevers.curry.FileReader.{closeStream, getLines, isReadable}
import com.datacrafts.digitalevers.sparseMatrix.normal.{save2File, unzipMatrix}
import com.google.gson.Gson
import scala.collection.mutable.ArrayBuffer
/**
* 此例程提供Scala对稀疏矩阵进行压缩解压模拟的操作方法
* 泛型方式
*/
object generic{
implicit val filePath = ""
def main(args: Array[String]): Unit = {
var test = Array.ofDim[Double](11,3)
test(5)(2) = 11.1
test(3)(1) = 5.2
var res = zipMatrix(test)(checkMatrix)("json_generic.txt")
val arr = unzipMatrix("json_generic.txt")
for(line <- arr){
for(elem <- line){
print(elem.toString + " ")
}
println()
}
}
/**
* 压缩稀疏矩阵并将其保存到文件中
*/
def zipMatrix[T](inArray:Array[Array[T]])(check:(Array[Array[T]])=>Array[Int])(implicit filePath:String) = {
val newMatrix = ArrayBuffer[Array[Any]]()
val res:Array[Int] = check(inArray)
newMatrix.append(Array(res(0),res(1),0))
for(i <- 0 until inArray.length){
for(j <- 0 until inArray(i).length){
if(inArray(i)(j) != 0){
newMatrix.append(Array(i,j,inArray(i)(j)))
}
}
}
val arr = newMatrix.toArray
val gson = new Gson()
val json = gson.toJson(arr)
if(filePath.isEmpty == true){
json
} else {
save2File(filePath,json)
}
}
/**
* 因为泛型的压缩数组数据类型不确定
* 所以这个隐式函数提供给 unzipMatrix 作隐式类型转换
* @param in
* @return
*/
implicit def any2Int(in:Any):Int = {
in.toString.toDouble.toInt
}
/**
* 从文件中读取数据并解压成稀疏矩阵
*/
def unzipMatrix(filePath:String) = {
val content = getLines(filePath) (isReadable) (closeStream)
if(content == ""){
throw new Exception("文件内容为空")
}
val res = ArrayBuffer[Array[Any]]()
val gson = new Gson()
val arr = gson.fromJson(content,classOf[Array[Array[Any]]])
for(i <- 0 until arr.length){
if(i == 0){
for(j <- 0 until arr(0)(0)){
val line = ArrayBuffer[Any]()
for(k <- 0 until arr(0)(1)){
line.append(0)
}
res.append(line.toArray)
}
///初始化
} else {
res(arr(i)(0))(arr(i)(1)) = arr(i)(2)
}
}
res.toArray
}
/**
* 检测数组的容积(长和宽)
* @param inArray
* @tparam T
* @return
*/
def checkMatrix[T](inArray:Array[Array[T]]):Array[Int] = {
if(inArray.length > 0){
val i = inArray.length
val j = inArray(0).length
Array(i,j)
} else {
Array(0,0)
}
}
}
package com.datacrafts.digitalevers.curry
import java.io.{BufferedReader, Closeable, File, FileReader}
import com.esotericsoftware.minlog.Log
/**
* 这段代码使用函数柯里化的功能实现了读取文件源并将其转为List数据
*
* 函数柯里化的精髓是使得函数在依赖其他函数的情况下实现可插拔,从而在函数与函数之间的调用上进行解耦
* 比如这段代码也可以在getLines底层函数上只保留 filename 一个参数,在函数体内直接调用 isReadable 和 closeStream 方法来进行
* 周边逻辑的实现,可以达到同样的效果,但是如果将来需要修改 isReadable 和 closeStream 的功能,不得不修改这两个方法的源代码
* 如果采用柯里化的形式 可以重新编写一个 isReadable 和 closeStream 的实现,在上层调用的时候直接将新函数作为参数传入即可
* 从而符合ocp原则。
*/
object File2List {
def main(args: Array[String]): Unit = {
var list = readFile("1.txt")
print(list)
}
def readFile (filename: String): List[String] = {
getLines(filename) (isReadable) (closeStream)
}
/**
* 柯里化后的函数
* @param filename
* @param isFileReadable
* @param closableStream
* @return
*/
private def getLines (filename: String) (isFileReadable: (File) => Boolean) (closableStream: (Closeable) => Unit): List[String] = {
val file = new File(filename)
if (isFileReadable (file) ) {
val readerStream = new FileReader(file)
val buffer = new BufferedReader(readerStream)
try {
var list: List[String] = List ()
var str = ""
var isReadOver = false
while (! isReadOver) {
str = buffer.readLine ()
if (str == null) isReadOver = true
else list = str :: list
}
list.reverse
} finally {
closableStream (buffer)
closableStream (readerStream)
}
} else {
List ()
}
}
/**
* 判断文件是否可读
* @param file
* @return
*/
def isReadable (file: File) = {
if (null != file && file.exists() && file.canRead() ) {
true
} else {
false
}
}
/**
*关闭打开的文件流
* @param stream
*/
def closeStream (stream: Closeable) {
if (null != stream) {
try {
stream.close
} catch {
case ex => Log.error( "[" +this.getClass.getName + ".closeStream] ", ex.getMessage)
}
}
}
}
近期评论