2013-07-23 4 views
5

У меня есть два списка: List(1,1,1) , List(1,0,1)Сравнение элементов в двух списках

Я хочу, чтобы получить следующее:

  1. Подсчет каждого элемента, который содержит 1 в первом списке и 0 в соответствующей список в том же положении и наоборот. В приведенном выше примере это будет 1, 0, так как первый список содержит 1 в среднем положении, а второй список содержит 0 в том же положении (средний).

  2. Счет каждого элемента, в котором 1 находится в первом списке, а 1 - во втором списке. В приведенном выше примере это два, так как в каждом соответствующем списке есть два 1. Я могу получить это, используя метод intersect класса List.

Я просто ищу ответ на пункт 1 выше. Я мог бы использовать итеративный подход для подсчета элементов, но есть ли более функциональный метод? Вот весь код:

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

ответ

11

Для первого:

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 

Для второго:

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

Не могли бы вы просто сказать «x => x._1 == 1 && x._2 == 0'? –

+7

На самом деле вы можете заменить 'filter (predicate) .size' с помощью' count (предикат) ' –

2

Почти такое же решение, которое было предложено Jatin, за исключением того, что вы может использовать List.count для лучшей делимости:

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

Почему не просто' l1.zip (l2) .count {case (x, y) => x! = Y} ' –

+0

Потому что я не думал использовать 'count', когда я писал его в первую очередь. Я обновляю ответ. ;) – Nicolas

0

1) Вы можете zip 2 списки, чтобы получить список (Int, Int), собирать только пар (1, 0) и (0, 1), замените (1, 0) с 1 и (0, 1) с -1 и получить сумму. Если подсчет (1, 0) и подсчета (0, 1) являются равно sum будет равна 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 

Вы можете использовать view метод для предотвращения создания промежуточных коллекций.

2) Вы можете использовать filter и length, чтобы получить количество элементов с некоторым условием:

(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

Вы также можете использовать foldLeft.Предполагая, что нет неотрицательные числа:

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

Вы можете рассчитывать все комбинации легко и иметь его в карту с

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

Хитрость является общим

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

Затем все, что вам нужно сделать, это поиск по карте

Смежные вопросы