vocales veces una txt separe repite repetidas que programa palabras palabra espacios cuantas contar consonantes como caracteres blanco archivo java java-8 java-stream word-count

veces - contar vocales y consonantes en java



Recuento de frecuencia de palabras Java 8 (8)

( NOTA: Vea las ediciones a continuación )

Como alternativa a la respuesta de Mounas , aquí hay un enfoque que cuenta la palabra en paralelo:

import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class ParallelWordCount { public static void main(String[] args) { List<String> list = Arrays.asList( "hello", "bye", "ciao", "bye", "ciao"); Map<String, Integer> counts = list.parallelStream(). collect(Collectors.toConcurrentMap( w -> w, w -> 1, Integer::sum)); System.out.println(counts); } }

EDITAR En respuesta al comentario, realicé una pequeña prueba con JMH, comparando toConcurrentMap y el enfoque groupingByConcurrent , con diferentes tamaños de lista de entrada y palabras aleatorias de diferentes longitudes. Esta prueba sugirió que el enfoque toConcurrentMap era más rápido. Al considerar cuán diferentes son estos enfoques "bajo el capó", es difícil predecir algo como esto.

Como una extensión adicional, basada en comentarios adicionales, extendí la prueba para cubrir las cuatro combinaciones de toMap , groupingBy , serial y paralela.

Los resultados siguen siendo que el enfoque toMap es más rápido, pero inesperadamente (al menos para mí) las versiones "concurrentes" en ambos casos son más lentas que las versiones en serie ...:

(method) (count) (wordLength) Mode Cnt Score Error Units toConcurrentMap 1000 2 avgt 50 146,636 ± 0,880 us/op toConcurrentMap 1000 5 avgt 50 272,762 ± 1,232 us/op toConcurrentMap 1000 10 avgt 50 271,121 ± 1,125 us/op toMap 1000 2 avgt 50 44,396 ± 0,541 us/op toMap 1000 5 avgt 50 46,938 ± 0,872 us/op toMap 1000 10 avgt 50 46,180 ± 0,557 us/op groupingBy 1000 2 avgt 50 46,797 ± 1,181 us/op groupingBy 1000 5 avgt 50 68,992 ± 1,537 us/op groupingBy 1000 10 avgt 50 68,636 ± 1,349 us/op groupingByConcurrent 1000 2 avgt 50 231,458 ± 0,658 us/op groupingByConcurrent 1000 5 avgt 50 438,975 ± 1,591 us/op groupingByConcurrent 1000 10 avgt 50 437,765 ± 1,139 us/op toConcurrentMap 10000 2 avgt 50 712,113 ± 6,340 us/op toConcurrentMap 10000 5 avgt 50 1809,356 ± 9,344 us/op toConcurrentMap 10000 10 avgt 50 1813,814 ± 16,190 us/op toMap 10000 2 avgt 50 341,004 ± 16,074 us/op toMap 10000 5 avgt 50 535,122 ± 24,674 us/op toMap 10000 10 avgt 50 511,186 ± 3,444 us/op groupingBy 10000 2 avgt 50 340,984 ± 6,235 us/op groupingBy 10000 5 avgt 50 708,553 ± 6,369 us/op groupingBy 10000 10 avgt 50 712,858 ± 10,248 us/op groupingByConcurrent 10000 2 avgt 50 901,842 ± 8,685 us/op groupingByConcurrent 10000 5 avgt 50 3762,478 ± 21,408 us/op groupingByConcurrent 10000 10 avgt 50 3795,530 ± 32,096 us/op

No tengo tanta experiencia con JMH, tal vez hice algo mal aquí: sugerencias y correcciones son bienvenidas:

import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; @State(Scope.Thread) public class ParallelWordCount { @Param({"toConcurrentMap", "toMap", "groupingBy", "groupingByConcurrent"}) public String method; @Param({"2", "5", "10"}) public int wordLength; @Param({"1000", "10000" }) public int count; private List<String> list; @Setup public void initList() { list = createRandomStrings(count, wordLength, new Random(0)); } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public void testMethod(Blackhole bh) { if (method.equals("toMap")) { Map<String, Integer> counts = list.stream().collect( Collectors.toMap( w -> w, w -> 1, Integer::sum)); bh.consume(counts); } else if (method.equals("toConcurrentMap")) { Map<String, Integer> counts = list.parallelStream().collect( Collectors.toConcurrentMap( w -> w, w -> 1, Integer::sum)); bh.consume(counts); } else if (method.equals("groupingBy")) { Map<String, Long> counts = list.stream().collect( Collectors.groupingBy( Function.identity(), Collectors.<String>counting())); bh.consume(counts); } else if (method.equals("groupingByConcurrent")) { Map<String, Long> counts = list.parallelStream().collect( Collectors.groupingByConcurrent( Function.identity(), Collectors.<String> counting())); bh.consume(counts); } } private static String createRandomString(int length, Random random) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { int c = random.nextInt(26); sb.append((char) (c + ''a'')); } return sb.toString(); } private static List<String> createRandomStrings( int count, int length, Random random) { List<String> list = new ArrayList<String>(count); for (int i = 0; i < count; i++) { list.add(createRandomString(length, random)); } return list; } }

Los tiempos solo son similares para el caso en serie de una lista con 10000 elementos y palabras de 2 letras.

Podría valer la pena verificar si para tamaños de lista aún más grandes, las versiones concurrentes finalmente superan a las seriales, pero actualmente no tienen el tiempo para ejecutar otro punto de referencia detallado con todas estas configuraciones.

¿Cómo contar la frecuencia de las palabras de List en Java 8?

List <String> wordsList = Lists.newArrayList("hello", "bye", "ciao", "bye", "ciao");

El resultado debe ser:

{ciao=2, hello=1, bye=2}


Aquí hay una manera de crear un mapa de frecuencia usando funciones de mapa.

List<String> words = Stream.of("hello", "bye", "ciao", "bye", "ciao").collect(toList()); Map<String, Integer> frequencyMap = new HashMap<>(); words.forEach(word -> frequencyMap.merge(word, 1, (v, newV) -> v + newV) ); System.out.println(frequencyMap); // {ciao=2, hello=1, bye=2}

O

words.forEach(word -> frequencyMap.compute(word, (k, v) -> v != null ? v + 1 : 1) );


Encuentra el artículo más frecuente en la colección, con genéricos:

private <V> V findMostFrequentItem(final Collection<V> items) { return items.stream() .filter(Objects::nonNull) .collect(Collectors.groupingBy(Functions.identity(), Collectors.counting())) .entrySet() .stream() .max(Comparator.comparing(Entry::getValue)) .map(Entry::getKey) .orElse(null); }

Calcular frecuencias de elementos:

private <V> Map<V, Long> findFrequencies(final Collection<V> items) { return items.stream() .filter(Objects::nonNull) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); }


Otros 2 centavos míos, dada una matriz:

import static java.util.stream.Collectors.*; String[] str = {"hello", "bye", "ciao", "bye", "ciao"}; Map<String, Integer> collected = Arrays.stream(str) .collect(groupingBy(Function.identity(), collectingAndThen(counting(), Long::intValue)));


Presentaré la solución que hice aquí (la que tiene la agrupación es mucho mejor :)).

static private void test0(List<String> input) { Set<String> set = input.stream() .collect(Collectors.toSet()); set.stream() .collect(Collectors.toMap(Function.identity(), str -> Collections.frequency(input, str))); }

Solo mi $ 0.02


Quiero compartir la solución que encontré porque al principio esperaba usar métodos de mapeo y reducción, pero era un poco diferente.

Map<String, Long> collect = wordsList.stream().collect(groupingBy(Function.identity(), counting()));

O para valores enteros:

Map<String, Integer> collect = wordsList.stream().collect(groupingBy(Function.identity(), summingInt(e -> 1)));

EDITAR

Agrego cómo ordenar el mapa por valor:

LinkedHashMap<String, Long> countByWordSorted = collect.entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> { throw new IllegalStateException(); }, LinkedHashMap::new ));


Si usa Eclipse Collections , puede convertir la List en una Bag .

Bag<String> words = Lists.mutable.with("hello", "bye", "ciao", "bye", "ciao").toBag(); Assert.assertEquals(2, words.occurrencesOf("ciao")); Assert.assertEquals(1, words.occurrencesOf("hello")); Assert.assertEquals(2, words.occurrencesOf("bye"));

Este código funcionará con Java 5 - 8.

Nota: Soy un committer para Eclipse Collections


public class Main { public static void main(String[] args) { String testString ="qqwweerrttyyaaaaaasdfasafsdfadsfadsewfywqtedywqtdfewyfdweytfdywfdyrewfdyewrefdyewdyfwhxvsahxvfwytfx"; long java8Case2 = testString.codePoints().filter(ch -> ch ==''a'').count(); System.out.println(java8Case2); ArrayList<Character> list = new ArrayList<Character>(); for (char c : testString.toCharArray()) { list.add(c); } Map<Object, Integer> counts = list.parallelStream(). collect(Collectors.toConcurrentMap( w -> w, w -> 1, Integer::sum)); System.out.println(counts); } }