Я не знаю, есть ли правильный способ получить размер списка в scala, но для вашей ситуации вы можете использовать последовательность.
Qusay Fantazia
Этот вопрос все еще без ответа? Спрашивает, потому что вы, возможно, забыли принять его.
Тобиас Колб
Ответы:
150
Несколько более чистая версия одного из других ответов:
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.groupBy(identity).mapValues(_.size)
давая Mapсчетчик для каждого элемента в исходной последовательности:
Map(banana ->1, oranges ->3, apple ->3)
Вопрос спрашивает, как найти количество конкретного предмета. При таком подходе решение потребовало бы отображения желаемого элемента на его значение счетчика следующим образом:
Как обсуждается здесь, это функция идентичности . Для функции groupByтребуется функция, которую она применяет к элементам, чтобы она знала, как их группировать. Альтернативой группировке строк в ответе по их идентификаторам может быть, скажем, группировка по их длине ( groupBy(_.size)) или по первой букве ( groupBy(_.head)).
ohruunuruus 09
2
Недостаток в том, что создается много бесполезной коллекции (потому что нужен только размер).
Ян
что, если бы я хотел определить карту аккумулятора в этом выражении вместо создания новой карты?
Несколько более чистая версияs.groupBy(identity).mapValues(_.size)
ohruunuruus
1
@ohruunuruus, это должен быть ответ (против комментария); я бы с энтузиазмом проголосовал за, если бы это было так (и выбрал бы его как лучший ответ, если бы я был ОП);
Дуг,
1
@doug немного новичок в SO и не был уверен, но рад
услужить
27
list.groupBy(i=>i).mapValues(_.size)
дает
Map[Int,Int]=Map(1->1,2->3,7->1,3->1,4->3)
Обратите внимание, что вы можете заменить (i=>i)встроенной identityфункцией:
люблю короткие решения с использованием встроенных библиотек
Рустам Алиев
14
val list =List(1,2,4,2,4,7,3,2,4)// Using the provided count method this would yield the occurrences of each value in the list:
l map(x => l.count(_ == x))List[Int]=List(1,3,3,3,3,1,1,3,3)// This will yield a list of pairs where the first number is the number from the original list and the second number represents how often the first number occurs in the list:
l map(x =>(x, l.count(_ == x)))// outputs => List[(Int, Int)] = List((1,1), (2,3), (4,3), (2,3), (4,3), (7,1), (3,1), (2,3), (4,3))
Хорошо, это то, что я искал, мне было грустно, что даже потоки Java (которые не очень хороши в некоторых аспектах) позволяют это за один проход, в то время как Scala не может.
Dici
9
Я столкнулся с той же проблемой, но хотел посчитать сразу несколько элементов ..
val s =Seq("apple","oranges","apple","banana","apple","oranges","oranges")
s.foldLeft(Map.empty[String,Int]){(m, x)=> m +((x, m.getOrElse(x,0)+1))}
res1: scala.collection.immutable.Map[String,Int]=Map(apple ->3, oranges ->3, banana ->1)
Интересно отметить, что карта со значением по умолчанию 0, специально разработанная для этого случая, демонстрирует худшую производительность (и не такую краткую, как groupBy)
Я немного подозрительно отношусь к этому тесту, так как неясно, каков размер данных. groupByРешение выполняет , toLowerно другие этого не делают. Также зачем использовать сопоставление с образцом для карты - просто используйте mapValues. Так что сверните это вместе, и вы получите def woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)- попробуйте это и проверьте производительность для списков различных размеров. Наконец, в других решениях, почему а) объявлять mapи б) делать его var ?? Just dow.foldLeft(Map.empty[Char, Int])...
samthebest
1
Спасибо за дополнительные данные (изменил свой голос :). Я думаю, причина в том, что реализация groupBy использует изменяемую карту Builders, которая оптимизирована для итеративных приращений. Затем он преобразует изменяемую карту в неизменяемую с помощью файла MapBuilder. Вероятно, под капотом тоже проводится ленивая оценка, чтобы ускорить работу.
samthebest
@samthebest Вы просто просматриваете счетчик и увеличиваете его. Я не вижу, что там можно кэшировать. В любом случае кеш должен быть картой того же типа.
Val
Я не говорю, что он что-то кеширует. Я полагаю, что увеличение производительности происходит из-за использования Builders и, возможно, некоторой ленивой оценки.
samthebest
@samthebest ленивая оценка = отложенная оценка (вызов по имени) + кеширование. Нельзя говорить о ленивых вычислениях, но не о кешировании.
Val
4
Я не получил размер списка, используя, lengthа, скорее, sizeкак один из приведенных выше ответов предложил это из-за проблемы, описанной здесь .
val list =List("apple","oranges","apple","banana","apple","oranges","oranges")
list.groupBy(x=>x).map(t =>(t._1, t._2.size))
Ух ты, 4 итерации исходной последовательности! Даже seq.groupBy(identity).mapValues(_.size)проходит только дважды.
WeaponsGrade
Количество итераций может не иметь значения для небольшой строки, такой как «Alphabet», но при работе с миллионами элементов в коллекции итерации, безусловно , имеют значение!
WeaponsGrade 01
2
Попробуйте это, должно сработать.
val list =List(1,2,4,2,4,7,3,2,4)
list.count(_==2)
Чем это отличается от ответа xiefei, данного семь лет назад?
jwvh
0
Вот довольно простой способ сделать это.
val data =List("it","was","the","best","of","times","it","was","the","worst","of","times")
data.foldLeft(Map[String,Int]().withDefaultValue(0)){case(acc, letter)=>
acc +(letter ->(1+ acc(letter)))}// => Map(worst -> 1, best -> 1, it -> 2, was -> 2, times -> 2, of -> 2, the -> 2)
Ответы:
Несколько более чистая версия одного из других ответов:
давая
Map
счетчик для каждого элемента в исходной последовательности:Вопрос спрашивает, как найти количество конкретного предмета. При таком подходе решение потребовало бы отображения желаемого элемента на его значение счетчика следующим образом:
источник
groupBy
требуется функция, которую она применяет к элементам, чтобы она знала, как их группировать. Альтернативой группировке строк в ответе по их идентификаторам может быть, скажем, группировка по их длине (groupBy(_.size)
) или по первой букве (groupBy(_.head)
).В коллекциях scala есть
count
:list.count(_ == 2)
источник
У меня была та же проблема, что и у Шарата Прабхала, и я получил другое (для меня более ясное) решение:
В результате:
источник
s.groupBy(identity).mapValues(_.size)
дает
Обратите внимание, что вы можете заменить
(i=>i)
встроеннойidentity
функцией:источник
источник
Начиная
Scala 2.13
, метод groupMapReduce делает это за один проход по списку:Это:
group
элементы списка (групповая часть группы MapReduce)map
s каждое сгруппированное вхождение значения до 1 (часть карты группы Map Reduce)reduce
s значений в группе значений (_ + _
) путем их суммирования (уменьшить часть groupMap Reduce ).Это однопроходная версия того, что можно перевести:
источник
Я столкнулся с той же проблемой, но хотел посчитать сразу несколько элементов ..
https://gist.github.com/sharathprabhal/6890475
источник
Stream
и принятый ответ приведет к достижению вашей цели - «один раз» плюс более четкий код.Если вы хотите использовать его так же, как
list.count(2)
вам нужно реализовать его с помощью неявного класса .источник
Короткий ответ:
Длинный ответ:
Используя Scalaz , дано.
затем все это (в порядке от менее упрощенного к более упрощенному)
Уступать
источник
Интересно отметить, что карта со значением по умолчанию 0, специально разработанная для этого случая, демонстрирует худшую производительность (и не такую краткую, как
groupBy
)производит
Любопытно, что самый лаконичный
groupBy
быстрее даже изменяемой карты!источник
groupBy
Решение выполняет ,toLower
но другие этого не делают. Также зачем использовать сопоставление с образцом для карты - просто используйтеmapValues
. Так что сверните это вместе, и вы получитеdef woGrouped(w: Word): Map[Char, Int] = w.groupBy(identity).mapValues(_.size)
- попробуйте это и проверьте производительность для списков различных размеров. Наконец, в других решениях, почему а) объявлятьmap
и б) делать его var ?? Just dow.foldLeft(Map.empty[Char, Int])...
Builder
s, которая оптимизирована для итеративных приращений. Затем он преобразует изменяемую карту в неизменяемую с помощью файлаMapBuilder
. Вероятно, под капотом тоже проводится ленивая оценка, чтобы ускорить работу.Builder
s и, возможно, некоторой ленивой оценки.Я не получил размер списка, используя,
length
а, скорее,size
как один из приведенных выше ответов предложил это из-за проблемы, описанной здесь .источник
Вот еще вариант:
источник
источник
используя кошек
источник
seq.groupBy(identity).mapValues(_.size)
проходит только дважды.Попробуйте это, должно сработать.
Он вернет 3
источник
Вот довольно простой способ сделать это.
источник