2012-07-03 6 views

答えて

9

shapelessあなたが書くことができます使用して、あなたがこれを行うことができます:

def toTuple[A <: Object](as:List[A]):Product = { 
    val tupleClass = Class.forName("scala.Tuple" + as.size) 
    tupleClass.getConstructors.apply(0).newInstance(as:_*).asInstanceOf[Product] 
} 
toTuple: [A <: java.lang.Object](as: List[A])Product 

scala> toTuple(List("hello", "world")) 
res15: Product = (hello,world) 
+0

+1非常に便利なランタイムエラーにつながることができます' List'から 'Tuple'を作成する方法を提供していません文字列からの割り当て。 var(a、b、c)= toTuple(myIter.toList)の場合は動作しません。 –

+1

Rubistro:その目的のために 'var List(a、b、c)= myIter.toList'を使うことができます。 –

14

あなたは本当にこれが無駄にあいまいですので、あなたの方法はProductを返すようにしたくありません。返されたオブジェクトをタプルとして使用できるようにするには、そのアリティを知る必要があります。だからあなたができることは、さまざまな手続きのために一連のtoTupleNメソッドを持つことです。便宜上、これらを暗黙のメソッドとしてSeqに追加することができます。

これはどう:

class EnrichedWithToTuple[A](elements: Seq[A]) { 
    def toTuple2 = elements match { case Seq(a, b) => (a, b) } 
    def toTuple3 = elements match { case Seq(a, b, c) => (a, b, c) } 
    def toTuple4 = elements match { case Seq(a, b, c, d) => (a, b, c, d) } 
    def toTuple5 = elements match { case Seq(a, b, c, d, e) => (a, b, c, d, e) } 
} 
implicit def enrichWithToTuple[A](elements: Seq[A]) = new EnrichedWithToTuple(elements) 

など、それを使用します。

scala> List(1,2,3).toTuple3 
res0: (Int, Int, Int) = (1,2,3) 
14

を@dhgが観察されるように、あなたはここに便利な何かを行うことができますフロントアップ、期待アリティを知って、場合。あなたがアップフロントアリティを知っていて、ひどいひどいハックを行うにはしたくない場合は

scala> import shapeless._ 
import shapeless._ 

scala> import Traversables._ 
import Traversables._ 

scala> import Tuples._ 
import Tuples._ 

scala> List(1, 2, 3).toHList[Int :: Int :: Int :: HNil] map tupled 
res0: Option[(Int, Int, Int)] = Some((1,2,3)) 
+0

しかし 'Shapeless'は、リストの長さはコンパイル時に定義されていない場合、それはクリーンアップのための –

3

は、あなたがしたいですかTupleかただProductです。後者のため:

case class SeqProduct[A](elems: A*) { 
    override def productArity: Int = elems.size 
    override def productElement(i: Int) = elems(i) 
} 

SeqProduct(List(1, 2, 3): _*) 
+0

' Tuple'もまた望んでいますので、 'TupleX'を必要とする' FunctionX.tupled'を使用できます。 'Product'ではなく(' ProductX'でも注意してください)。 – metasim

1

@Kim Stebelのアイデアに基づいて、私はseqからタプルを作成するシンプルなユーティリティを書きました。

import java.lang.reflect.Constructor 

/** 
* Created by Bowen Cai on 1/24/2015. 
*/ 
sealed trait Product0 extends Any with Product { 

    def productArity = 0 
    def productElement(n: Int) = throw new IllegalStateException("No element") 
    def canEqual(that: Any) = false 
} 
object Tuple0 extends Product0 { 
    override def toString() = "()" 
} 

case class SeqProduct(elems: Any*) extends Product { 
    override def productArity: Int = elems.size 
    override def productElement(i: Int) = elems(i) 
    override def toString() = elems.addString(new StringBuilder(elems.size * 8 + 10), "(" , ",", ")").toString() 
} 

object Tuples { 

    private[this] val ctors = { 
    val ab = Array.newBuilder[Constructor[_]] 
    for (i <- 1 to 22) { 
     val tupleClass = Class.forName("scala.Tuple" + i) 
     ab += tupleClass.getConstructors.apply(0) 
    } 
    ab.result() 
    } 

    def toTuple(elems: Seq[AnyRef]): Product = elems.length match { 
    case 0 => Tuple0 
    case size if size <= 22 => 
     ctors(size - 1).newInstance(elems: _*).asInstanceOf[Product] 
    case size if size > 22 => new SeqProduct(elems: _*) 
    } 

} 
+0

ありがとう、@ xコマンダー。これは私が必要としたものです。私は_toTuple_を_AnyRef_ではなく_Any_のシーケンスに適用したいので、elesの型を_Seq [Any] _に置き換え、 'size <= 22'の場合の式を' val refs = for(e < - elems)は、e.asInstanceOf [AnyRef] ctors(size - 1).newInstance(refs:_ *)asInstanceOf [Product] 'を返します(ここの回答に基づいています:http://stackoverflow.com/questions/16751484 /オブジェクトとしての整数への強制的なラッピング)) – Phasmid

関連する問題