3 öğeli bir listeyi 3 boyutlu bir demete nasıl dönüştürebilirim?
Örneğin, diyelim ki ben var val x = List(1, 2, 3)
ve bunu (1, 2, 3)
. Bunu nasıl yapabilirim?
3 öğeli bir listeyi 3 boyutlu bir demete nasıl dönüştürebilirim?
Örneğin, diyelim ki ben var val x = List(1, 2, 3)
ve bunu (1, 2, 3)
. Bunu nasıl yapabilirim?
x match { case a :: b :: c :: Nil => (a, b, c); case _ => (0, 0, 0) }
sonuç türünün sabit olduğunu göz önünde bulundurun ve not edinTuple3[Int,Int,Int]
List
, demetlereHList
ve demetlerden dönüşüme izin veren Shapeless ' türüne bakabilirsiniz ( github.com/milessabin/… ). Belki kullanım durumunuz için geçerlidir.
Yanıtlar:
Bunu tip güvenli bir şekilde yapamazsınız. Neden? Çünkü genel olarak bir listenin uzunluğunu çalışma zamanına kadar bilemeyiz. Ancak bir demetin "uzunluğu" kendi türünde kodlanmalı ve dolayısıyla derleme zamanında bilinmelidir. Örneğin şeker (1,'a',true)
türü vardır . Tupleların bu kısıtlamaya sahip olmasının nedeni, homojen olmayan türleri işleyebilmeleri gerektiğidir.(Int, Char, Boolean)
Tuple3[Int, Char, Boolean]
case class Vec3[A](_1: A, _2: A, _3: A)
map
çalıştığını tanımlamanız gerekir
Bunu, ölçek çıkarıcıları ve desen eşleştirmesi ( bağlantı ) kullanarak yapabilirsiniz :
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
Bir demet veren
t: (Int, Int, Int) = (1,2,3)
Ayrıca, Listenin boyutundan emin değilseniz bir joker karakter operatörü kullanabilirsiniz.
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
şekilsiz kullanan bir örnek :
import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled
Not: derleyicinin HList'teki Listeyi dönüştürmek için bazı tür bilgilerine ihtiyacı vardır, neden tür bilgilerini toHList
yönteme iletmeniz gerekir
Shapeless 2.0 bazı sözdizimini değiştirdi. İşte şekilsiz kullanan güncellenmiş çözüm.
import shapeless._
import HList._
import syntax.std.traversable._
val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled
Ana sorun, .toHList türünün önceden belirtilmesi gerektiğidir. Daha genel olarak, demetler sınırlı oldukları için, yazılımınızın tasarımı farklı bir çözümle daha iyi sunulabilir.
Yine de, statik olarak bir liste oluşturuyorsanız, bunun gibi, şekilsiz kullanarak da bir çözüm düşünün. Burada, doğrudan bir HList oluşturuyoruz ve tür, derleme zamanında kullanılabilir. Bir HList'in hem List hem de Tuple türlerinden özelliklere sahip olduğunu unutmayın. yani, bir Tuple gibi farklı türlerde öğelere sahip olabilir ve standart koleksiyonlar gibi diğer işlemler arasında eşleştirilebilir. HListlerin alışması biraz zaman alır, ancak yeniyseniz yavaş ilerleyin.
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil
scala> val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)
scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)
Sadeliğine ve herhangi bir uzunluktaki listeler için olmamasına rağmen, tür açısından güvenlidir ve çoğu durumda cevaptır:
val list = List('a','b')
val tuple = list(0) -> list(1)
val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))
Listeyi adlandırmak veya tekrarlamak istemediğinizde başka bir olasılık (umarım birisi Seq / head bölümlerinden kaçınmanın bir yolunu gösterebilir):
val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head
FWIW, birkaç alanı ilk kullanıma sokacak bir demet istedim ve demet atamasının sözdizimsel şekerini kullanmak istedim. ÖRNEĞİN:
val (c1, c2, c3) = listToTuple(myList)
Bir listenin içeriğini atamak için de sözdizimsel şeker olduğu ortaya çıktı ...
val c1 :: c2 :: c3 :: Nil = myList
Yani aynı sorunu yaşıyorsanız demetlere gerek yok.
val List(c1, c2, c3) = myList
Bunu tür güvenli bir şekilde yapamazsınız. Scala'da listeler, bazı türlerdeki öğelerin keyfi uzunlukta dizileridir. Tip sisteminin bildiği kadarıyla x
, keyfi uzunlukların bir listesi olabilir.
Aksine, bir demetinin uyuşması derleme zamanında bilinmelidir. x
Bir demet tipine atamaya izin vermek için tip sisteminin güvenlik garantilerini ihlal eder .
Aslında, teknik nedenlerden ötürü, Scala kayıtları 22 öğe ile sınırlıydı , ancak sınır artık 2.11'de mevcut değil. Vaka sınıfı sınırı 2.11 https://github.com/scala/scala/pull/2305'te kaldırılmıştır.
22 öğeye kadar listeleri dönüştüren ve daha büyük listeler için bir istisna oluşturan bir işlevi manuel olarak kodlamak mümkün olabilir. Scala'nın gelecek bir özellik olan şablon desteği, bunu daha kısa hale getirecektir. Ama bu çirkin bir hack olurdu.
List.size <23 olduğundan çok eminsen kullan:
def listToTuple[A <: Object](list:List[A]):Product = {
val class = Class.forName("scala.Tuple" + list.size)
class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product
scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)
Bu, aşağıdakiler shapeless
kullanılarak daha az standart şablonla da yapılabilir Sized
:
scala> import shapeless._
scala> import shapeless.syntax.sized._
scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))
Tür açısından güvenlidir: None
tuple boyutu yanlışsa, ancak tuple boyutunun değişmez veya final val
(dönüştürülebilmesi için shapeless.Nat
) olması gerekir .
Desen Eşleştirmeyi Kullanma:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
List
/ uzunluğu Tuple
bilinen bir sabitse uygulanabilir.
2015 yazısı. For Tom Crockett cevabı daha edilmesi netleştirilmesi , burada gerçek bir örnektir.
İlk başta kafam karıştı. Çünkü ben yapabileceğin Python'dan geliyorum tuple(list(1,2,3))
.
Scala dilinin kısaltması mı? (cevap - Scala veya Python ile ilgili değil, statik tip ve dinamik tip ile ilgili.)
Bu, Scala'nın bunu neden yapamayacağını bulmaya çalışmama neden oluyor.
Aşağıdaki kod örneği toTuple
, tür açısından güvenli toTupleN
ve güvenli olmayan türlere sahip bir yöntemi uygular toTuple
.
toTuple
Dönüş türü yani yöntem olup, çalışma zamanında tip uzunluğa, derleme zamanında, yani herhangi bir tür uzunlukta bilgi almak Product
çok Python'ın gibi olan tuple
gerçekten (her pozisyonda bir tip ve türde bir uzunluğu).
Bu yol, tür uyuşmazlığı veya IndexOutOfBoundException
. (bu yüzden Python'un uygun liste başı ücretsiz öğle yemeği değildir.)
Aksine, toTupleN
derleme zamanını güvenli kılan, kullanıcının sağladığı uzunluk bilgisidir .
implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple: Product = elements.length match {
case 2 => toTuple2
case 3 => toTuple3
}
def toTuple2 = elements match {case Seq(a, b) => (a, b) }
def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}
val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad !
val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!
bunu da yapabilirsin
Listede yineleyerek ve her öğeyi tek tek uygulayarak.
val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String)
val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({
case (f,x) => f.asInstanceOf[Any=>Any](x)
}).asInstanceOf[(Int,Double,String)]
def toTuple(x: List[Int]): R
, R türü ne olmalıdır?