2013-07-23 24 views
5

Ho due liste: List(1,1,1) , List(1,0,1)Confrontando articoli in due liste

voglio ottenere le seguenti:

  1. Un conteggio di ogni elemento che contiene un 1 nella prima lista e uno 0 nella corrispondente lista alla stessa posizione e viceversa. Nell'esempio sopra questo sarebbe 1, 0 poiché il primo elenco contiene un 1 in posizione centrale e il secondo elenco contiene uno 0 nella stessa posizione (al centro).

  2. Un conteggio di ogni elemento in cui 1 è nel primo elenco e 1 è anche nel secondo elenco. Nell'esempio sopra questo è due poiché ci sono due 1 in ogni lista corrispondente. Posso ottenere questo usando il metodo intersect di List di classe.

Sto solo cercando una risposta al punto 1 sopra. Potrei usare un approccio iterativo per contare gli oggetti ma esiste un metodo più funzionale? Qui è l'intero codice:

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)) 
    } 
} 

risposta

11

Per la prima:

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 

Per la seconda:

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

Non potresti semplicemente dire 'x => x._1 == 1 && x._2 == 0'? –

+7

In realtà è possibile sostituire 'filter (predicate) .size' con solo' count (predicato) ' –

2

Quasi la stessa soluzione che è stata proposta da Jatin, tranne che si possibile utilizzare List.count per una migliore leggibilità:

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

Perché non solo' l1.zip (l2) .count {case (x, y) => x! = Y} ' –

+0

Perché non ho pensato di usare 'count' quando l'ho scritto per primo. Sto aggiornando la risposta. ;) – Nicolas

0

1) Si potrebbe zip 2 liste per ottenere l'elenco dei (Int, Int), raccogliere solo le coppie (1, 0) e (0, 1), sostituire (1, 0) con 1 e (0, 1) con -1 e ottenere sum. Se conte di (1, 0) e conte di (0, 1) sono gli stessi della sum sarebbe pari 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 

Si potrebbe utilizzare view metodo per impedire la creazione di collezioni intermedi.

2) Si potrebbe usare filter e length per ottenere il conto di elementi con qualche condizione:

(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

È anche possibile utilizzare foldLeft.Se non ci sono numeri non negativi:

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

potete contare tutte le combinazioni facilmente e l'abbiano in una mappa con

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) 
*/ 

Il trucco è un comune

// 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 
*) 

Quindi tutto quello che dovete fare è cercare sulla mappa