2011-08-22 10 views

cevap

18

eşleşen deseni kullanabilmesi

last fonksiyon Lists gelince, onlar için "etkili bir sabit zaman" alır, çünkü Vectors için gayet iyi, ben, lineer zaman alır Anlamada println'dan kaçınmanızı öneririz. Bazen bir koleksiyonun ortasında meydana gelen bir hatayı takip etmek için yararlı olabilir, ancak aksi halde yeniden düzenleme ve test etmenin zor olduğu kodlara yol açar.

Genel olarak, herhangi bir tür yan etkinin nerede meydana gelebileceğini kısıtlayabiliyorsanız, genellikle hayat daha kolay hale gelir. Bunu yerine:

for (line <- myData) { 
    println("}, {") 
} 

Sen yazabilirsiniz: Ben de çıktıda her satırın içeriğini istediğini burada bir tahmin alacağım

val lines = for (line <- myData) yield "}, {" 
println(lines mkString "\n") 

!

val lines = for (line <- myData) yield (line + "}, {") 
println(lines mkString "\n") 

sadece doğrudan mkString kullanılırsa yine daha iyi olurdu rağmen - bu ne için olduğunu bu! Önce bir String üreten konum nasıl

val lines = myData.mkString("{", "\n}, {", "}") 
println(lines) 

Not sonra tek işlemde yazdırmadan. Bu yaklaşım kolayca ayrı yöntemlere bölünebilir ve sınıfınızda toString uygulamak veya oluşturulan String'i testlerde denetlemek için kullanılabilir.

6

Sen bir örnek olarak TraversableOnce özelliğin addString fonksiyonunu alabilir yazdırmak için ben almak için bir yol

for (line <- myData) { 
    println("}, {") 
    } 

var mı olduğunu varsayalım. Senin durumunda

def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = { 
    var first = true 

    b append start 
    for (x <- self) { 
    if (first) { 
     b append x 
     first = false 
    } else { 
     b append sep 
     b append x 
    } 
    } 
    b append end 

    b 
} 

, ayırıcı }, { ve bitiş }

+0

+1. Standart kütüphanede nasıl yapıldığını görmek güzel. –

28

sen yararlanmak için kodunuzu refactor Can yerleşik mkString?

scala> List(1, 2, 3).mkString("{", "}, {", "}") 
res1: String = {1}, {2}, {3} 
2

yerleşik kullanmak için mkString fonksiyonu istemiyorsanız, sen yapabilirsiniz

for (line <- lines) 
    if (line == lines.last) println("last") 
    else println(line) 

GÜNCELLEME gibi bir şey: Açıklamalarda belirtildiği didierd gibi, bu çözüm son değere çünkü yanlış Birkaç kez oluşabilir, onun answer onun daha iyi bir çözüm sağlar. Daha ileri gitmeden önce

@tailrec 
def printLines[A](l: List[A]) { 
    l match { 
    case Nil => 
    case x :: Nil => println("last") 
    case x :: xs => println(x); printLines(xs) 
    } 
} 
+1

Yinelemeli çözüm gayet iyi. Son öğenin değerinin başka hiçbir yerde gerçekleşmediğini bilemezseniz == lines.last olanı yanlıştır. –

+0

@didierd teşekkürler, onu özledim. Cevaptaki hatayı işaret ettim. – 4e6

+0

'==' yerine 'eq' kullanarak denedim ve hala çalışmıyor - Dizeler bir önbellek tutmalı, ki bu biraz acıdır –

12

mkstring kullanımı hakkında daha önce söylediklerinize tam olarak katılıyorum ve sonuncu yerine ilk yinelemeyi ayırt ediyorum. Son olarak, scala koleksiyonlarının birbirinden ayırt etmenizi ister misiniz? Tüm öğeleri döndüren son satır init yöntemine sahiptir. Yani

for(x <- coll.init) workOnNonLast(x) 
workOnLast(coll.last) 

(ilk ama ilk ve ve hepsi baş ve kuyruk tersinin init ve last olmanın sıralama) yapabilirsiniz. Ancak, yapıya bağlı olarak, pahalı olabilirler. Vector'da, hepsi hızlı. List'da, baş ve kuyruk temelde ücretsiz iken, init ve last, listenin uzunluğunda doğrusaldır. toplama boş olabilir zaman headOption ve lastOption haklı mkString işaret vardır

for (x <- coll.lastOption) workOnLast(x) 
1

Diğer cevaplar ile workOnlast yerine size yardımcı olabilir ve verilerin normal miktarı için ben de o kullanırsınız. Ancak, mkStringmkString, StringBuilder aracılığıyla bellekte son sonucu oluşturan (biriktiren) (biriktirir) oluşturur (0,). Bu, sahip olduğumuz veri miktarına bağlı olarak her zaman arzu edilmez.

Bu durumda, tek istediğimiz "yazdırmak" ise, önce büyük sonucu oluşturmaya gerek yoktur (ve belki bundan kaçınmak isteriz). Tüm elemanlar üzerinde dolaşır ve mantıksal bir değer ile, sırayla her eleman geçen operation çağırır

def forEachIsLast[A](iterator: Iterator[A])(operation: (A, Boolean) => Unit): Unit = { 
    while(iterator.hasNext) { 
    val element = iterator.next() 
    val isLast = !iterator.hasNext // if there is no "next", this is the last one 
    operation(element, isLast) 
    } 
}  

:

bu yardımcı işlevinin uygulama göz önünde bulundurun. Öğe, geçen son ise true değeridir.

Senin durumunda

böyle kullanılabilir:

forEachIsLast(myData) { (line, isLast) => 
    if(isLast) 
    println("}") 
    else 
    println("}, {") 
} 

Biz burada şu avantajları vardır:

  • Her elemanı çalışır birer birer mutlaka sonuç birikmeye olmadan bellek (istemediğiniz sürece).
  • Tüm koleksiyonu belleğe sığdırmak için belleğe yüklemesi gerekmediğinden, yorulursa yineleyici sormanız yeterlidir. Eğer * İlk * yineleme için farklı hareket etmek için istenilen davranışı planı ayrı eğer, sıklıkla çok daha kolay, Nicolas'ın cevabı zaten işaret @ gibi vb büyük bir dosyadan veya ağdan
+2

Ya da, biraz daha zarif, belki: 'forEachIsLast' sadece 'val it = seq olabilir.toIterator it.foreach {operation (_, it.hasNext)} ' –

+0

Çok teşekkürler @ TheArchetypalPaul! Önerinizi önerinize dayalı bir uygulama kullanmak için düzenledim. –

İlgili konular