2013-03-22 13 views
6

DÜZENLEME: Sadece benim filtre olarak aynı etkiye sahiptir düzleştirmek ve ben Scala 2.9.2 kullanıyorumScala koşullu liste inşaat

harita ve bazı koşullara göre bir liste oluşturmak istediğini aklımızda tutuyoruz. aşağıdaki gibi

t1 :: t2 :: cond(p, t3) :: t4 

istediğim davranışıdır: koşul (bu durumda, t3) mesnet p ve T türü bir değer alarak bir fonksiyondur

, aşağıdaki göz önünde bulundurun. p doğruysa, bu vermelidir: Muhtemelen bu tamamen yanlış şekilde düşünüyorum

List[T](t1, t2, t4) 

ama mücadele ediyorum:

List[T](t1, t2, t3, t4) 

p yanlış olarak değerlendirilirse, bu vermelidir zarif bir çözüm bulmak için. Her yerde Seçenek içerebilir ve daha sonra filtre, ama bu okumak için oldukça zor kodu yapar:

def cond[T](p : => Boolean, v : T) : Option[T] = 
{ 
    p match 
    { 
     case true => Some(v) 
     case false => None 
    } 
} 

Bu

aşağıdaki sağlar: o gerektirdiğinden ancak

scala> (Some(1) :: Some(2) :: cond(true, 3) :: Some(4) :: Nil).flatten 
res4: List[Int] = List(1, 2, 3, 4) 

scala> (Some(1) :: Some(2) :: cond(false, 3) :: Some(4) :: Nil).flatten 
res5: List[Int] = List(1, 2, 4) 

, en zarif çözüm, değil Kullanıcı tüm koşulsuz öğelerini Some() içinde sarmak ve sonunda düzleştirmek için hatırlamak için. Daha şık bir çözüm düşünen var mı?

cevap

5

Listeler nasıl verilir?

List(1,2,3) ++ cond(false, 3) ++ List(4) 
+0

Bu, ancak 1 :: 2 :: 3 yapım yöntemiyle uyuşmadığı için ideal değildir: kullanımı hatırlamanızı gerektirir ++ yerine genel durumda çalışmaz Yani :: – paulmdavies

4

oluşturmayı deneyin ve senin durumunda yeni bir liste filtreleme:

@inline def cond[T](p : => Boolean, v : T) : List[T] = if(p) v::Nil else Nil 

ve sonra bu şekilde bunları kullanarak

List[T](t1, t2, t3, t4).filter(p) 
+1

bazı durumlarda - koşul p_i eleman t_i özgüdür - ve p_i sadece t_i listede olup olmadığını etkilemelidir değerlendirme sonucu, nerede j, t_j değil =! ben – paulmdavies

0

Uygun seçmek için dizini bilmek gerekiyorsa Bu nedenle, endeksleri değerlerle eşleştirmek için zipWithIndex değerini kullanabilir ve ardından endeksi sonuçtan düşürmek ve önceki kodlamayı kodlamak için filter yerine collect kullanın. Bir muhafazanın icate seçimi ve uygulaması. Ör:

List(1, 4, 9, 16, 25).zipWithIndex.collect { case (n, i) if (n + i) % 3 <= 1 => n } 
res0: List[Int] = List(1, 16) 
3

tip yanlış çünkü Yani, bu standart liste ile çalışacak imkan yok: bunu bir şey vermek istiyorum oysa ::T liste türü olan tip [A >: T] unsurunu beklediğini bu tür bir elementi üretebilir veya üretmeyebilir. Bununla birlikte, yalnızca isteğe bağlı olarak bir sonraki öğe üreten bir şeyleri almaktan oldukça memnun olan bir yöntemi tanımlayabilmemesinin bir nedeni yoktur. List kendisi mühürlenir, bu yüzden doğrudan uzatmak olamaz, ama biz oldukça kolay ihtiyacımız davranışı çoğaltabilir: Biz temelde listeyi yeniden

trait QList[+T] { 

    def hd : T 
    def tl : QList[T] 

    def ?::[A >: T](hd : A) : QList[A] = new ?::[A](hd, this) 
    def ?::[A >: T](hd : => Option[A]) : QList[A] = hd match { 
    case Some(a) => ?::(a) 
    case None => this 
    } 
} 

case object QNil extends QList[Nothing] { 
    def hd = throw new Exception("Head of empty list") 
    def tl = throw new Exception("Tail of empty list") 
} 
case class ?::[+T](val hd: T, val tl : QList[T]) extends QList[T] 

def cond[T](p : => Boolean, v : T) : Option[T] = 
{ 
    p match 
    { 
    case true => Some(v) 
    case false => None 
    } 
} 

val truelist = 1 ?:: 2 ?:: 3 ?:: cond(true, 4) ?:: 5 ?:: QNil 
val falselist = 1 ?:: 2 ?:: 3 ?:: cond(false, 4) ?:: 5 ?:: QNil 

ama bir durumun götüren bir aşırı başa ekleyin operasyonu ile masset .

Doğru yöntem olan başka sınıfa örtük dönüştürme kullanarak standart listesine ?:: yöntemi eklemek mümkündür. Sen aksi takdirde bu örtülü değer sınıfları için mükemmeldir türden bir şey olduğu için bir utanç olduğunu 2.9.2 kullanıyorsanız söz, ama biz bunları gerek yoktur, onlar sadece işleri kolaylaştıracak:

class ConditionallyAppend[T](tl : List[T]) { 
    def ?::[A >: T](hd : A) : List[A] = hd :: tl 
    def ?::[A >: T](x : => Option[A]) : List[A] = x match { 
    case Some(a) => a :: tl 
    case None => tl 
    } 
} 

implicit def ListToConditionallyAppend[A](x : List[A]) = new ConditionallyAppend(x) 

Ve şimdi bunu yapabilirsiniz:???

val truelist = 1 :: 2 :: 3 :: kon (true, 4) :: 5 :: Nil

truelist:? Liste [herhangi] = listesi (1, 2, 3, 4, 5)

Bu:?

val FalseList = 1 :: 2 :: 3 :: koşul (yanlış, 4) :: 5 :: Nil

FalseList:? Liste [herhangi] = Liste (1, 2, 3, 5)

+0

Ben briefl y, bunun yerine '?' yerine ''' operatörünü varsayılan olarak geçersiz kılabileceğimizi önermek için düzenledik. Yapabiliriz, ama işe yaramıyor. List 'kovaryant olduğu 'Çünkü standart başa getirebilir o süper türü olarak çıkarabiliriz şeyi kabul edecek ve böylece sadece içinde bir' None' içeren bir 'listesi [Herhangi]' verecektir. – Impredicative