Skip to content

Instantly share code, notes, and snippets.

@dotNetTree
Last active June 7, 2022 01:33
Show Gist options
  • Save dotNetTree/9035dda235cb171025bdbbcc7c9e114f to your computer and use it in GitHub Desktop.
Save dotNetTree/9035dda235cb171025bdbbcc7c9e114f to your computer and use it in GitHub Desktop.
Code Spitz 90 - 코틀린 언어편 (1) 과제
val trim = """[^.\d-+*/()]""".toRegex()
fun trim(v: String): String = v.replace(trim, "")
fun repMMtoP(v: String) = v.replace("--", "+")
fun repMtoPM(v: String) = v.replace("-", "+-")
val groupMD = """((?:\+|\+-)?[.\d]+)([*/])((?:\+|\+-)?[.\d]+)""".toRegex()
tailrec fun removeMultiDiv(v: String): String = groupMD.find(v).let {
if (it != null) {
val (target, left, op, right) = it.groupValues
val leftValue = left.replace("+", "").toDouble()
val rightValue = right.replace("+", "").toDouble()
val result = when (op) {
"*" -> leftValue * rightValue
"/" -> leftValue / rightValue
else -> throw Throwable("invalid operator $op")
}
removeMultiDiv(v.replace(target, "+$result"))
} else v
}
fun calcWithBracket(v: String): Double {
return v
.let { v.drop(1).dropLast(1) }
.let { trim(it) }
.let { repMMtoP(it) }
.let { repMtoPM(it) }
.let { removeMultiDiv(it) }
.split("""(\++)""".toRegex())
.fold(0.0) { accu, curr ->
if (curr.isBlank()) { accu } else accu + curr.toDouble()
}
}
tailrec fun removeBracket(v: String): String {
return """\([.\d+\-*/]+\)""".toRegex().findAll(v).let {
if (it.count() == 0) v
else removeBracket(
it.fold(v) { acc, cur ->
val target = cur.value
val ret = calcWithBracket(target)
acc.replace(target, "$ret")
}
)
}
}
fun calc(v: String): Double = removeBracket("(${trim(v)})").toDouble()
fun main(args: Array<String>) {
val exps: Array<String> = arrayOf(
"16 / 2 / 2 / 2",
"-2 -3 + 0.4",
"-2 * (-3 + 0.4) / -0.2",
"-2 * (-3 + 0.4) / -0.2 + .55",
"-2 - (-3 + -8 * (7 + 3)) + (0.4 / -0.2)",
)
for (exp in exps) {
println("$exp = ${calc(exp)}")
}
}
@dotNetTree
Copy link
Author

dotNetTree commented Jun 6, 2022

@hannut91 코드 리뷰 감사합니다. 리뷰 해주신 내용 반영하였습니다.

그런데, 한가지 질문이 있습니다.

그리고 하나 더, 변수를 선언한 곳과 사용하는 곳은 거리가 가까울수록 좋습니다. 특히 상수가 아닌 변수는 선언한 곳과 사용하는 곳이 멀어질수록 그 사이에 변수에 무슨 짓을 할지 모르기 때문에, 그 사이를 모두 의심의 눈초리로 코드를 봐야 합니다.

class가 등장하게 되면 프로퍼티와 선언(변수)와 사용처인 메소드가 물리적으로 매우 떨어지게 되는데요. 이 경우에도 같은 룰을 적용해야 하는건가요?

그리고 guard pattern은 sequence로 부터 Interactor 객체를 얻어내는 것보단 count method를 활용하는게 더 좋을 것습니다.

@hannut91
Copy link

hannut91 commented Jun 6, 2022

class가 등장하게 되면 프로퍼티와 선언(변수)와 사용처인 메소드가 물리적으로 매우 떨어지게 되는데요. 이 경우에도 같은 룰을 적용해야 하는건가요?

가능한 가까우면 좋은데, 무조건 그런 것은 아닙니다! 클래스가 등장하면 변수를 위에 놓고 메서드를 쓰니 꼭 그렇게 되지는 않겠죠 ㅎㅎ 변수를 사용할 때도 때로는 변수를 모아놓는 것이 좋을 때가 있는 것 같아요.

그리고 guard pattern은 sequence로 부터 Interactor 객체를 얻어내는 것보단 count method를 활용하는게 더 좋을 것습니다.

count 메서드가 있었군요 감사합니다!

@dotNetTree
Copy link
Author

@hannut91 감사합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment