2015-10-25 4 views
1

У меня есть итератор, содержащий несколько пар значений ключа. напримерScala - подсчитать количество вхождений каждого ключа в Iterator

(жень, хуг) (Ken, ZXY) (жень, ASD) (Ken, ASDF)

Результаты должны быть

(жень, 2) (ken, 2)

Как использовать функцию count (или любую другую) для подсчета количества вхождений каждой клавиши в итераторе этой конкретной коллекции.

Edit: Коллекция что итератор represend в моем потребительной случае имеет большое количество записей, возможно в диапазоне миллионов, нет мне нужен самый эффективный (меньше времени сложности) способ сделать это. Я узнал, что метод count был довольно быстрым и что его можно каким-то образом использовать для получения результата желания.

ответ

5

Вы можете groupBy ключ и затем подсчета вхождений каждого ключа:

val iterator = 
    Iterator(("jen","xyz"), ("ken","zxy"), ("jen","asd"), ("ken", "asdf")) 

iterator.toList.groupBy(_._1).mapValues(_.length).toList 
// List[(String, Int)] = List((jen,2), (ken,2)) 
+1

Peter, см. Мой ответ ниже. Использование 'groupBy' для получения списков и подсчет каждого из этих списков по' length' будет довольно неэффективным. –

+1

@JasonLenderman, "довольно неэффективно"? Это почти наверняка не повлияет на огромное, подавляющее большинство случаев. Микрооптимизации просто глупы, пока вы их не очень нуждаетесь (что очень редко). ** Plus **, если вы действительно обеспокоены этой крошечной, крошечной долей эффективности, вам, вероятно, следует переписать * ваш * ответ, чтобы не использовать 'foldLeft'; в конце концов, цикл 'while' всегда будет намного более эффективным ... – dhg

+0

@dhg, метод' groupBy' создает новый «Список» для каждого ключа, и каждый из этих «списков» создается в памяти. Кроме того, для вычисления длины требуется дополнительный обход для каждого списка.Если количество различных ключей, которые повторяются (и количество раз, когда они происходят), являются небольшими, то это, вероятно, не большая проблема, но для некоторых приложений это может быть очень плохо. Что касается использования цикла while, я этого не делал, потому что считаю, что это микро-оптимизация. Зачем? Потому что это приведет только к * постоянному коэффициенту * улучшения * независимо * от приложения или данных. –

8

Подход, который Питер Neyens предлагает будет работать, но это может быть очень неэффективным (время и память) для некоторых приложений из-за путь toList, groupBy и length. Как правило, гораздо более эффективно собирать счета непосредственно в карту и избегать всего ненужного создания Lists.

import scala.collection.TraversableOnce 
import scala.collection.mutable.HashMap 

def counts[T](xs: TraversableOnce[T]): Map[T, Int] = { 
    xs.foldLeft(HashMap.empty[T, Int].withDefaultValue(0))((acc, x) => { acc(x) += 1; acc}).toMap 
} 

После того, как вы определили метод counts вы можете применить его к итератора пар ключ-значение, например, так:

val iter: Iterator[(String, String)] = ??? 
val keyCounts = counts(iter.map(_._1)) 

Метод counts определено выше работает хорошо Iterators над большим числом значения, например

val iter = Iterator.range(0, 100000000).map(i => (i % 1931, i)) 
val countMap = counts(iter.map(_._1)) 
// Map(645 -> 51787, 892 -> 51787, 69 -> 51787, 1322 -> 51786, ...) 

работает отлично, в то время как подход, предложенный в ответ Петра, то есть

val iter = Iterator.range(0, 100000000).map(i => (i % 1931, i)) 
val countMap = iter.toList.groupBy(_._1).mapValues(_.length).toMap 

пыхтит прочь на некоторое время, и в конечном итоге приводит к OutOfMemoryError. Причина, по которой он терпит неудачу, - это из-за ненужного создания List.

+1

Эй, что с ненужной картой? Как насчет метода расширения 'countBy (f: A => K)'? –

+1

Насколько я понял, ОП не интересовался этой ценностью, его интересовало только количество раз, когда каждый ключ встречался. Таким образом, на карте есть только выталкивание значения в каждой паре ключ-значение. «CountBy» будет хорошим обобщением, но я думаю, вам все равно нужно сделать «карту» перед «countBy» для приложения OP. –

+0

@JasonLenderman Вы правы, меня интересует только подсчет количества раз, когда каждый ключ встречается, независимо от значения, содержащегося в этих ключах. –

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