Problem
Spreadsheet cells are referenced by column and row identifiers. Columns are labeled with alphabetical characters, starting with "A", "B", "C", ...; rows are numbered from 1 in ascending order. Write a function that takes in a string identifying a range of cells in a spreadsheet and returns an ordered list of cells which compose that range.
Example:
"A3:D5" -> ["A3", "A4", "A5", "B3", "B4", "B5", "C3", "C4", "C5", "D3", "D4", "D5"]
"A3:D4" -> ["A3", "A4", "B3", "B4", "B5", "C3", "C4", "C5", "D3", "D4"]
Here is scala implementation of the same ,
import scala.language.postfixOps
object PrintSpreadSheet extends App {
val validAlphabets = ('A' to 'Z').toSeq
def cells(range: String): Seq[String] = {
val corners = (range split ":") flatMap { corner =>
Seq(corner.head, corner.last)
}
val rows = (corners filter (r => validAlphabets.contains(r))) sorted
val cols = (corners filter (c => !validAlphabets.contains(c))) sorted
(rows.head to rows.last) flatMap { r =>
(cols.head to cols.last) map { c =>
r.toString + ":" + c.toString
}
}
}
cells("A1:D5") foreach println
}
2 Answers 2
I couldn't get your code to compile until I took out the sorted
. The output was still good so I don't know what purpose it was supposed to serve.
There's no point in casting validAlphabets
to a Seq[Char]
. As a Range[Char]
the contains()
method still works. Better still would be to cast it to a Set[Char]
. Then the syntax is more concise and the lookup is faster.
val rows = corners filter validAlphabets
val cols = corners filter (!validAlphabets(_))
Due to the use of .head
and .last
, this solution won't handle rows past 9
. There are also a number of input errors that it won't catch. These can be addressed if you use a Regex to parse the input.
def cells(range: String): Seq[String] = {
val format = "([A-Z])(\\d+):([A-Z])(\\d+)".r
val format(colStart, rowStart, colEnd, rowEnd) = range
for {
c <- colStart.head to colEnd.head //from String to Char
r <- rowStart.toInt to rowEnd.toInt //from String to Int
} yield s"$c:$r" //back to String
}
This will throw if the input string doesn't match the expected format. If you'd prefer it print the error and return nothing (an empty Seq[String]
) then you can use a match
statement instead, with a default case _ =>
for the format failure.
Notice that I use a for
comprehension here. Whenever you see a map()
inside a flatMap()
that's a flag indicating that a for
might do the same thing in a clearer/cleaner manner.
-
\$\begingroup\$ Code is compiling for me, here is same code in a online compiler scastie.scala-lang.org/eQxRuAvfR9qgCwNMiapGmg Also sorted is needed to handle input like "D5:A1" , else it will return empty seq. without sorted version - scastie.scala-lang.org/fD8FBWMDRRyzdvPvv4bazg I thought about using regex and agree it makes validation straightforward. But I am not very comfortable in writing regex (specially in an interview), learning it. How about working with Strings and using some thing like this - scala> ("A233" take 1, "A233" drop 1) res92: (String, String) = (A,233) \$\endgroup\$vikrant– vikrant2019年01月05日 05:30:31 +00:00Commented Jan 5, 2019 at 5:30
-
\$\begingroup\$ But I do agree regex is best and I should learn it. It makes it super simple. I accept it as a answer. \$\endgroup\$vikrant– vikrant2019年01月05日 05:34:51 +00:00Commented Jan 5, 2019 at 5:34
You're failing to handle columns beyond column Z (which should be AA) and rows beyond row 9. Your variable naming is also reversed: the columns are designated using letters and the rows are designated using numbers.
Explore related questions
See similar questions with these tags.