2013-07-23 17 views
5

Mam dwóch list: List(1,1,1) , List(1,0,1)Porównywanie przedmiotów w dwóch listach

Chcę uzyskać następujące:

  1. badanie liczby każdego elementu, który zawiera 1 na pierwszej liście i 0 w analogicznym lista na tej samej pozycji i odwrotnie. W powyższym przykładzie będzie to 1, 0, ponieważ pierwsza lista zawiera 1 w środkowej pozycji, a druga lista zawiera 0 w tej samej pozycji (środkowej).

  2. Liczba wszystkich elementów, gdzie 1 znajduje się na pierwszej liście, a 1 na drugiej liście. W powyższym przykładzie jest to dwa, ponieważ na każdej z nich znajdują się dwie cyfry 1. Mogę to uzyskać za pomocą metody przecięcia listy klas.

Po prostu szukam odpowiedzi do punktu 1 powyżej. Mogę użyć iteracyjnego podejścia do liczenia przedmiotów, ale czy istnieje bardziej funkcjonalna metoda? Oto cały kod:

class Similarity { 
    def getSimilarity(number1: List[Int], number2: List[Int]) = { 
    val num: List[Int] = number1.intersect(number2) 
    println("P is " + num.length) 
    } 
} 

object HelloWorld { 
    def main(args: Array[String]) { 
    val s = new Similarity 
    s.getSimilarity(List(1, 1, 1), List(1, 0, 1)) 
    } 
} 

Odpowiedz

11

Dla pierwszego z nich:

scala> val a = List(1,1,1) 
a: List[Int] = List(1, 1, 1) 

scala> val b = List(1,0,1) 
b: List[Int] = List(1, 0, 1) 

scala> a.zip(b).filter(x => x._1==1 && x._2==0).size 
res7: Int = 1 

Na drugi:

scala> a.zip(b).filter(x => x._1==1 && x._2==1).size 
res7: Int = 2 
+1

Nie możesz po prostu powiedzieć "x => x._1 == 1 && x._2 == 0"? –

+7

Właściwie możesz zastąpić 'filter (predicate) .size' za pomocą' count (predicate) ' –

2

Prawie to samo rozwiązanie, które zostało zaproponowane przez Jatin, z tym że można użyć numeru List.count, aby uzyskać lepszą widoczność:

def getSimilarity(l1: List[Int], l2: List[Int]) = 
    l1.zip(l2).count({case (x,y) => x != y}) 
+2

Dlaczego nie tylko' l1.zip (l2) .count {case (x, y) => x! = Y} ' –

+0

Ponieważ nie myślałem o używaniu 'count', kiedy napisałem to pierwsze. Aktualizuję odpowiedź. ;) – Nicolas

0

1) Mogłeś zip 2 list do listy (Int, Int) się zebrać tylko pary (1, 0) i (0, 1) wymienić (1, 0) z 1 i (0, 1) z -1 i uzyskać sumę. Jeśli liczba (1, 0) i zliczania (0, 1) są takie same sum byłaby równa 0:

val (l1, l2) = (List(1,1,1) , List(1,0,1)) 

(l1 zip l2).collect{ 
    case (1, 0) => 1 
    case (0, 1) => -1 
}.sum == 0 

Można użyć view metodę zapobiegania tworzenia kolekcji pośrednich.

2) Można użyć filter i length aby uzyskać liczbę elementów z pewnym warunkiem:

(l1 zip l2).filter{ _ == (1, 1) }.length 
(l1 zip l2).collect{ case (1, 1) =>() }.length 
2
a.zip(b).filter(x => x._1 != x._2).size 
1

Można również użyć foldLeft.Zakładając, że nie istnieją nieujemne liczby:

a.zip(b).foldLeft(0)((x,y) => if (y._1 + y._2 == 1) x + 1 else x) 
7

można liczyć wszystkie kombinacje łatwo i miały je w mapy z

def getSimilarity(number1 : List[Int] , number2 : List[Int]) = { 

    //sorry for the 1-liner, explanation follows 
    val countMap = (number1 zip number2) groupBy (identity) mapValues {_.length} 

} 

/* 
* Example 
* number1 = List(1,1,0,1,0,0,1) 
* number2 = List(0,1,1,1,0,1,1) 
* 
* countMap = Map((1,0) -> 1, (1,1) -> 3, (0,1) -> 2, (0,0) -> 1) 
*/ 

Sztuką jest częstym jeden

// zip the elements pairwise 

(number1 zip number2) 

/* List((1,0), (1,1), (0,1), (1,1), (0,0), (0,1), (1,1)) 
* 
* then group together with the identity function, so pairs 
* with the same elements are grouped together and the key is the pair itself 
*/ 

.groupBy(identity) 

/* Map((1,0) -> List((1,0)), 
*  (1,1) -> List((1,1), (1,1), (1,1)), 
*  (0,1) -> List((0,1), (0,1)), 
*  (0,0) -> List((0,0)) 
*) 
* 
* finally you count the pairs mapping the values to the length of each list 
*/ 

.mapValues(_.length) 

/* Map((1,0) -> 1, 
*  (1,1) -> 3, 
*  (0,1) -> 2, 
*  (0,0) -> 1 
*) 

Wszystko co musisz zrobić, to sprawdzić na mapie

Powiązane problemy