2017-02-19 19 views
5

Nowość w Scala. I iteruję pętlę for 100 razy. 10 razy chcę, aby spełniony został warunek "a" i 90 razy warunek "b". Jednak chcę, żeby 10 a występowało losowo.Scala: dla pętli pasującej do ints na liście

Najlepszym sposobem, jaki mogę sobie wyobrazić, jest stworzenie wartości 10 losowych liczb całkowitych, a następnie przepuszczenie od 1 do 100 znaków.

Na przykład:

val z = List.fill(10)(100).map(scala.util.Random.nextInt) 

z: List[Int] = List(71, 5, 2, 9, 26, 96, 69, 26, 92, 4) 

Wtedy coś takiego:

for (i <- 1 to 100) { 
    whenever i == to a number in z: 'Condition a met: do something' 
else { 
    'condition b met: do something else' 
    } 
} 

Próbowałem za pomocą contains i == i =! ale nic nie wydawało się do pracy. Jak inaczej mogę to zrobić?

+0

Am I czegoś brakuje lub nie dla '(dyr <- r = scala.util.Random.shuffle (Lista. fill (10) (true) + List.fill (90) (false))) {if (cond) ... else // not cond ...} 'zrób to? –

Odpowiedz

5

Twoja generacja liczb losowych może dać duplikaty ... czy to w porządku? Oto w jaki sposób można łatwo wygenerować 10 niepowtarzalne numery 1-100 (generując rozmieszczane losowo kolejność 1-100 i zajmując pierwsze dziesięć):

val r = scala.util.Random.shuffle(1 to 100).toList.take(10) 

teraz po prostu można podzielić zakres 1-100 do tych, którzy są zawarte w losowo generowanych listy i tych, którzy nie są:

val (listOfA, listOfB) = (1 to 100).partition(r.contains(_)) 

teraz robić, co chcesz z tych dwóch list, np:

println(listOfA.mkString(",")) 
println(listOfB.mkString(",")) 

oczywiście, zawsze można po prostu przejść przez jedna lista jednym:

(1 to 100).map { 
    case i if (r.contains(i)) => println("yes: " + i) // or whatever 
    case i => println("no: " + i) 
} 

Co uważasz za prosty dla pętli w rzeczywistości nie ma. To zrozumiałe i jest to cukier składniowy, który usuwa sugestie połączeń map, płaskich map i filtrów. Tak, można go używać w taki sam sposób, jak w klasycznej pętli for, ale dzieje się tak tylko dlatego, że List jest w rzeczywistości monadą. Bez wchodzenia w zbyt wiele szczegółów, jeśli chcesz robić rzeczy w idiomatyczny sposób Scala ("funkcjonalny" sposób), powinieneś unikać pisania klasycznych iteracji dla pętli i wolisz zdobywać kolekcję danych, a następnie mapować ich elementy, aby wykonaj to, czego potrzebujesz. Zwróć uwagę, że kolekcje mają za sobą naprawdę bogatą bibliotekę, która pozwala na wywoływanie fajnych metod, takich jak partition.

EDIT (kompletność):

Ponadto, należy unikać skutków ubocznych, lub przynajmniej przesunąć je tak daleko w dół drogi, jak to możliwe. Mówię o drugim przykładzie z mojej odpowiedzi. Powiedzmy, że naprawdę musisz się zalogować rzeczy (używałbyś programu rejestrującego, ale println jest wystarczająco dobry dla tego przykładu). Robienie tego w ten sposób jest złe. Należy pamiętać, że w takim przypadku można użyć foreach zamiast map, ponieważ nie zbiera się wyników, a jedynie wykonuje efekty uboczne.

Dobrym sposobem byłoby obliczenie potrzebnych rzeczy przez zmodyfikowanie każdego elementu w odpowiedni ciąg. Więc obliczyć potrzebne łańcuchy i gromadzić je w results:

val results = (1 to 100).map { 
    case i if (r.contains(i)) => ("yes: " + i) // or whatever 
    case i => ("no: " + i) 
} 

// do whatever with results, e.g. print them 

Teraz results zawiera listę stu „tak X” i „Nie X” strun, ale nie robić brzydkie rzeczy i przeprowadzić rejestrację jako efekt uboczny w procesie mapowania.Zamiast tego zmapowałeś każdy element kolekcji na odpowiadający ciąg (zauważ, że oryginalna kolekcja pozostaje nienaruszona, więc jeśli (od 1 do 100) została zachowana pewna wartość, to wciąż tam jest, mapowanie tworzy nową kolekcję) i teraz możesz zrobić cokolwiek chcesz z nim, np przekazać go do rejestratora. Tak, w pewnym momencie musisz zrobić "brzydki efekt uboczny" i zalogować rzeczy, ale przynajmniej będziesz miał specjalną część kodu, aby to zrobić, a nie będziesz mieszał go w logikę mapowania, która sprawdza, czy numer jest zawarte w losowej kolejności.

+1

Przyjemny połów, jeśli chodzi o możliwe duplikaty - to jeden z tych subtelnych błędów, które pewnie nie zostaną zauważone przez chwilę :) – Eric

+0

Hah tak, szczególnie w większych kolekcjach – slouc

+1

Dużo się tutaj nauczyłem @slouc - doceń tę kompleksową odpowiedź :) – RDJ

3
(1 to 100).foreach { x => 
    if(z.contains(x)) { 
    // do something 
    } else { 
    // do something else 
    } 
} 

lub użyć częściową funkcję tak:

(1 to 100).foreach { 
    case x if(z.contains(x)) => // do something 
    case _ => // do something else 
}