Scala 基于集合的多任务分配
编辑 最初的问题是“集合到元组”,因为我假设我需要一个元组来执行变量多重赋值。事实证明,可以直接对集合执行变量多重赋值。相应地重新命名该问题 原创 有一个简单的Seq[String]派生自正则表达式,我想将其转换为元组 最直接的方法是什么 我目前有:Scala 基于集合的多任务分配,scala,collections,tuples,Scala,Collections,Tuples,编辑 最初的问题是“集合到元组”,因为我假设我需要一个元组来执行变量多重赋值。事实证明,可以直接对集合执行变量多重赋值。相应地重新命名该问题 原创 有一个简单的Seq[String]派生自正则表达式,我想将其转换为元组 最直接的方法是什么 我目前有: val(clazz, date) = captures match { case x: Seq[String] => (x(0), x(1)) } 这是可以的,但我的路由层有一堆正则表达式匹配的路由,我将对它们执行val(a、b、c)多
val(clazz, date) = captures match {
case x: Seq[String] => (x(0), x(1))
}
这是可以的,但我的路由层有一堆正则表达式匹配的路由,我将对它们执行val(a、b、c)多重分配(捕获组总是已知的,因为如果正则表达式不匹配,则不会处理路由)。最好有一个比match{case..=>}更精简的解决方案
在Scala中将集合转换为元组的最短单行程序是什么?您可以使用Scalaz中的
|>
操作符使它稍微好一点
scala> val captures = Vector("Hello", "World")
captures: scala.collection.immutable.Vector[java.lang.String] = Vector(Hello, World)
scala> val (a, b) = captures |> { x => (x(0), x(1)) }
a: java.lang.String = Hello
b: java.lang.String = World
如果您不想使用Scalaz,您可以自己定义|>
,如下所示:
scala> class AW[A](a: A) {
| def |>[B](f: A => B): B = f(a)
| }
defined class AW
scala> implicit def aW[A](a: A): AW[A] = new AW(a)
aW: [A](a: A)AW[A]
scala> val S = Seq
S: scala.collection.Seq.type = scala.collection.Seq$@157e63a
scala> val S(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
编辑:
或者,类似于@ziggystar的建议:
scala> val Vector(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
您可以使其更加简洁,如下所示:
scala> class AW[A](a: A) {
| def |>[B](f: A => B): B = f(a)
| }
defined class AW
scala> implicit def aW[A](a: A): AW[A] = new AW(a)
aW: [A](a: A)AW[A]
scala> val S = Seq
S: scala.collection.Seq.type = scala.collection.Seq$@157e63a
scala> val S(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
根据@ziggystar在评论中的建议,您可以执行以下操作:
val (clazz, date) = { val a::b::_ = capture; (a, b)}
或
如果在确定列表类型之前验证了它,请注意
Seq
的长度,因为即使列表大小为0或1,代码也会运行 这不是问题的答案,但可能会以不同的方式解决问题
你知道你可以像这样匹配一个
xs:List[String]
:
val a :: b :: c :: _ = xs
这会将列表的前三个元素分配给a、b、c
?您可以在val
声明中匹配其他内容,如Seq
,就像在case
语句中一样。请确保注意匹配错误:
您的问题最初是关于在正则表达式中分配单个捕获组的,它已经允许您直接从它们分配:
scala> val regex = """(\d*)-(\d*)-(\d*)""".r
regex: scala.util.matching.Regex = (\d*)-(\d*)-(\d*)
scala> val regex(a, b, c) = "29-1-2012"
d: String = 29
m: String = 1
y: String = 2012
显然,您也可以在案例中使用这些:
scala> "29-1-2012" match { case regex(d, m, y) => (y, m, d) }
res16: (String, String, String) = (2012,1,29)
然后根据需要对它们进行分组。Seqs到tuple
要从序列执行多重赋值,请执行以下操作
val Seq(clazz, date) = captures
如您所见,无需限制为List
s;如果长度不匹配,此代码将抛出一个MatchError
(在您的情况下,这很好,因为这意味着您犯了错误)。然后您可以添加
(clazz, date)
重新创建元组
匹配的元组
然而,Jed Wesley Smith发布了一个解决方案,它避免了这个问题,并更好地解决了原始问题。特别是,在您的解决方案中,您有一个未指定长度的Seq,因此如果您犯了错误,编译器不会告诉您;改用元组,编译器可以帮助您(即使它不能对照regexp进行检查)。对我来说,主要问题是不同的元组具有不同的类型,因此我不知道您是否可以使用返回不同大小元组的函数。此外,在您的示例中,match
中应该始终有一个转义格,为了避免出现问题,您还应该注意Seq
可以是长度您知道可以匹配xs:List[String]
像这样:val a::b::c::=xs
要获取列表的前三个元素?@Chris,除非正则表达式匹配,否则路径是不匹配的,所以我总是知道集合的长度。此外,集合类型始终为string类型。我可以做“val(a,b)=(捕获(0),捕获(1))”,但我正在寻找更多的东西generalized@ziggystar,+1不知道,非常直接的解决方案;-)@ziggystar,+1。在看到你的建议后,我的回答感觉有点愚蠢。嗯,我也可以做“val(a,b)=捕获匹配{case x=>(x(0),x(1))}”,没有任何魔力。保存几个字符并不能证明完全使用FP是正确的,在本例中,我使用@ziggystar的简单性;-)不是Ruby或Groovy无法追踪的魔力,而是复杂性/必须摸索意图方面的魔力。要打入钉子(解决问题),在可能的情况下,使用锤子(内置语言功能),然后再使用螺丝刀(FP)。+1,是的,这是一个非常非常好的解决此特定问题的方法。假设这需要Scalaz?对于斯卡拉来说,老实说,托尼·莫里斯静脉的FP方法在这一点上对我来说完全是莫名其妙的。在某一点上,我会看到FP光,但现在我主要关注Scala本身。说到这里,我希望2.10和反思很快就会到来!否则,我将别无选择,只能深入Scalaz以验证这些无反射的案例类。@virtualeyes,我厌倦了人们在所有错误的地方贴上“复杂”标签。在使用该词之前,您是否试图理解|>
?它只是一个函数应用程序,但从右到左。换句话说,f(x)
=x |>f
。为什么是那个方向?因为它有助于类型推断。在这种情况下,使用从左到右的方向时,必须指定函数参数类型。i、 e.val(a,b)=((x:Vector[String])=>(x(0),x(1))(捕获)
@virtualeyes,编辑没有使用任何Scalaz的东西。顺便说一句,为什么不直接做val clazz::date::=捕获
?更直接地说,我会按照@ziggystar的建议再次做,“val clazz::date=captures”,集合的长度和类型是已知的,除非正则表达式本身匹配,否则路径是不匹配的。我错过了它,很抱歉,我没有很好地理解@ziggystar的建议,所以我认为我的解决方案会改进它,但它没有。编辑:我的答案提供了一个元组,现在我记得我为什么写它:-)我喜欢大家叫他“@”ziggystar:)对,可以手动处理捕获(0),捕获(1);更喜欢ziggystar的解决方案……它不是问题的“答案”,而是问题的“答案”question@virtualeyes它不会将集合转换为元组。那些以后将要离开的人