Scala:如何提高其他字母

发布于 2025-01-30 22:23:51 字数 1154 浏览 2 评论 0原文

在一次采访中,我被问到这个问题。她想要在Scala而不是Java中的答案。 我的回答是以爪哇为中心。请注意,您无法使用角色索引来决定是否大写和小写。您能找到一种以Scala为中心的更好的方法吗?我想不出任何在这里有帮助的弦乐函数。专注于消除对VAR的需求。我使用尾部递归(之后)将其重写,但是答案效率低下,因此我坚持使用此以Java为中心的答案。

object Cap extends App {
  def _capitalizeEveryOtherLetter(str: String): String = {
    val s2: Array[Char] = str.toCharArray
    var capitalize: Boolean = true
    val arr: Array[Char] = (for (c <- s2)  yield  {
      if (!Character.isLetter(c)) {
        c
      } else if (capitalize) {
        capitalize = false
        val newChar = Character.toUpperCase(c)
        newChar
      } else {
        capitalize = true
        val newChar = Character.toLowerCase(c)
        newChar
      }
    })
    new String(arr)
  }
  val s1: String = "*7yTuu(i&^giuisKJSU&Y"
  println(s"${_capitalizeEveryOtherLetter(s1)}")
}

预期输出

*7YtUu(I&^gIuIsKjSu&Y

相似,但与如何将其他所有字符转换为字符串中的大小情况,因为它依赖于索引,这对此问题无效。

I was asked this question in an interview. She wanted the answer in scala not java.
My answer was java centric. Note that you can NOT use the character index to decide whether to uppercase and lowercase. Can you find a better way to make it scala centric? I can't think of any StringOps builtin functions that would help here. Focus on removing the need for var. I rewrote it using tail recursion (afterwards) but the answer was inefficient so I'm sticking with this java centric answer.

object Cap extends App {
  def _capitalizeEveryOtherLetter(str: String): String = {
    val s2: Array[Char] = str.toCharArray
    var capitalize: Boolean = true
    val arr: Array[Char] = (for (c <- s2)  yield  {
      if (!Character.isLetter(c)) {
        c
      } else if (capitalize) {
        capitalize = false
        val newChar = Character.toUpperCase(c)
        newChar
      } else {
        capitalize = true
        val newChar = Character.toLowerCase(c)
        newChar
      }
    })
    new String(arr)
  }
  val s1: String = "*7yTuu(i&^giuisKJSU&Y"
  println(s"${_capitalizeEveryOtherLetter(s1)}")
}

The expected output is

*7YtUu(I&^gIuIsKjSu&Y

Similar but not the same as How to convert every other character to upper case in a string since it relies on indexing which is not valid for this question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏日落 2025-02-06 22:23:51

如果您只有字母,那么Scala的方式将是

input.grouped(2).map(_.capitalize).mkString("")

跳过非书信的炭,使它变得更加复杂:首先找出应该如何转换每个字母,然后替换它们:

val letters = input.filter(_.isLetter).grouped(2).flatMap(_.capitalize)
input.map { c => if (c.isLetter) letters.next else c }

但是这可能太“聪明”以进行面试:)
(嗯,取决于您在哪里面试)。

“官方”的Scala方法是“使用状态的遍历/变换”是(尾部)递归,或者(对于更简单的情况)foldleft带有累加器。而且,避免将事物附加到其他答案中提到的字符串或集合的效率低下的诀窍是向后构建列表,并最终将其逆转。

input.foldLeft[(Boolean, List[Char])](true -> Nil) { 
  case ((x, ac), c) if !c.isLetter => (x, c::ac)
  case ((true, ac), c) => (false, c.toUpper :: ac)
  case ((_, ac), c) => (true, c :: ac)
}._2.reverse.mkString("")

由于您的问题被标记为tail-recursion,因此这是一种尾巴恢复的方式(与上面的折叠并没有什么不同):

   @tailrec
   def upSome(
       chars: List[Char], 
       state: Boolean = true, 
       result: List[Char]
   ): List[Char] = (state, chars) match { 
     case (_, Nil) => result.reverse
     case (_, c::tail) if !c.isLetter => upSome(tail, state, c::result)
     case (true, c::tail) => upSome(tail, false, c::result)
     case (_, c::tail) => upSome(tail, true, c::result)
   }

您将使用它作为
upsome(input.tolist).mkstring(“”)

The scala way if you only had letters would be something like

input.grouped(2).map(_.capitalize).mkString("")

Skipping non-letter chars makes it somewhat more complicated: first figure out how each letter should be transformed, then replace them:

val letters = input.filter(_.isLetter).grouped(2).flatMap(_.capitalize)
input.map { c => if (c.isLetter) letters.next else c }

But this is probably too "clever" for an interview :)
(well, depends where you are interviewing).

The "official" scala approach to "traverse/transform with state" is either (tail) recursion or (for simpler cases) foldLeft with an accumulator. And the trick to avoid both mutability and the inefficiency of appending things to strings or collections mentioned in the other answer is building a list backwards, and reversing it in the end.

input.foldLeft[(Boolean, List[Char])](true -> Nil) { 
  case ((x, ac), c) if !c.isLetter => (x, c::ac)
  case ((true, ac), c) => (false, c.toUpper :: ac)
  case ((_, ac), c) => (true, c :: ac)
}._2.reverse.mkString("")

Since your question is labeled tail-recursion, here is a tail-recursive way (it's not really all that different from the foldLeft above):

   @tailrec
   def upSome(
       chars: List[Char], 
       state: Boolean = true, 
       result: List[Char]
   ): List[Char] = (state, chars) match { 
     case (_, Nil) => result.reverse
     case (_, c::tail) if !c.isLetter => upSome(tail, state, c::result)
     case (true, c::tail) => upSome(tail, false, c::result)
     case (_, c::tail) => upSome(tail, true, c::result)
   }

You would use it as
upSome(input.toList).mkString("")

独留℉清风醉 2025-02-06 22:23:51

由于字符串操作很昂贵,我只会使用StringBuilderfoldleft

def capitalizeEveryOtherLetter(str: String): String = {
  val sb = new StringBuilder(str.size)
  
  str.foldLeft(false) {
    case (flag, char) =>
      val isLetter = char.isLetter
      if (isLetter && flag) {
        sb += char.toUpper
        false
      } else {
        sb += char.toLower
        isLetter || flag
      }
  }
  
  sb.result()
}

您可以看到运行的代码在这里

Since string manipulation is expensive I would just use a StringBuilder and a foldLeft

def capitalizeEveryOtherLetter(str: String): String = {
  val sb = new StringBuilder(str.size)
  
  str.foldLeft(false) {
    case (flag, char) =>
      val isLetter = char.isLetter
      if (isLetter && flag) {
        sb += char.toUpper
        false
      } else {
        sb += char.toLower
        isLetter || flag
      }
  }
  
  sb.result()
}

You can see the code running here.

墟烟 2025-02-06 22:23:51

另一个(功能更大?)一个,避开了保持“我们是降低套管还是掉掉壳”状态的需求:

val xs  = "the quick brown fox jumps over the lazy dog";

val fs = 
 LazyList.continually(LazyList((c:Char) =>c.toUpper, (c:Char)=>c.toLower)).flatten;


(xs zip fs).map{case (c, f) => f(c)}.mkString

尽管我可能会误解了问题的意图 - 这交替出现上贴上和较低的评估,而无需考虑它是否是一封信。或不。我离开它是因为这是一种有趣的替代方法

Another (more functional?) one, that sidesteps the need to keep a "are we lower casing or uppercasing" status:

val xs  = "the quick brown fox jumps over the lazy dog";

val fs = 
 LazyList.continually(LazyList((c:Char) =>c.toUpper, (c:Char)=>c.toLower)).flatten;


(xs zip fs).map{case (c, f) => f(c)}.mkString

It's possible I mis-interpreted the intent of the question though - this alternates upppercasing and lowercasing without regard to whether it's a letter or not. I leave it because it's an interesting alternate approach

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文