Manipulating tuples

血红的双手。 提交于 2019-12-10 13:02:59

问题


Is there a way to manipulate multiple values of a tuple without using a temporary variable and starting a new statement?

Say I have a method that returns a tuple and I want to do something with those values inline.

e.g. if I want to split a string at a certain point and reverse the pieces

def backToFront(s: String, n:Int) = s.splitAt(n)...

I can do

val (a, b) = s.splitAt(n)
b + a 

(requires temporary variables and new statement) or

List(s.splitAt(n)).map(i => i._2 + i._1).head

(works, but seems a bit dirty, creating a single element List just for this) or

s.splitAt(n).swap.productIterator.mkString

(works for this particular example, but only because there happens to be a swap method that does what I want, so it's not very general).

The zipped method on tuples seems just to be for tuples of Lists.

As another example, how could you turn the tuple ('a, 'b, 'c) into ('b, 'a, 'c) in one statement?


回答1:


Tuples are just convenient return type, and it is not assumed that you will make complicated manipulations with it. Also there was similar discussion on scala forums.

About the last example, couldn't find anything better than pattern-matching.

('a, 'b, 'c) match { case (a, b, c) => (b, a ,c) }



回答2:


Unfortunately, the built-in methods on tuples are pretty limited.

Maybe you want something like these in your personal library,

def fold2[A, B, C](x: (A, B))(f: (A, B) => C): C = f(x._1, x._2)
def fold3[A, B, C, D](x: (A, B, C))(f: (A, B, C) => D): D = f(x._1, x._2, x._3)

With the appropriate implicit conversions, you could do,

scala> "hello world".splitAt(5).swap.fold(_ + _)
res1: java.lang.String = " worldhello"

scala> (1, 2, 3).fold((a, b, c) => (b, c, a))
res2: (Int, Int, Int) = (2,3,1)

An alternative to the last expression would be the "pipe" operator |> (get it from Scalaz or here),

scala> ('a, 'b, 'c) |> (t => (t._2, t._3, t._1))
res3: (Symbol, Symbol, Symbol) = ('b,'c,'a)

This would be nice, if not for the required annotations,

scala> ("hello ", "world") |> (((_: String) + (_: String)).tupled)
res4: java.lang.String = hello world



回答3:


How about this?

s.splitAt(n) |> Function.tupled(_ + _)

[ Edit: Just noticed your arguments to function are reversed. In that case, you will have to give up placeholder syntax and instead go for: s.splitAt(n) |> Function.tupled((a, b) => b + a) ]

For your last example, can't think of anything better than a pattern match (as shown by @4e6.)




回答4:


With the current development version of shapeless, you can achieve this without unpacking the tuple:

import shapeless.syntax.std.tuple._

val s = "abcdefgh"
val n = 3

s.splitAt(n).rotateRight[shapeless.Nat._1].mkString("", "", "") // "defghabc"

I think you shouldn't have to wait too long (matter of days I'd say) before the syntax of the methods of the last line get cleaned, and you can simply write

s.splitAt(n).rotateRight(1).mkString


来源:https://stackoverflow.com/questions/7129849/manipulating-tuples

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!