जावा 8 में सूची के शब्दों की आवृत्ति को कैसे गिनें?शब्द आवृत्ति गणना जावा 8
List <String> = Lists.newArrayList("hello", "bye", "ciao", "bye", "ciao");
परिणाम होना चाहिए:
{ciao=2, hello=1, bye=2}
जावा 8 में सूची के शब्दों की आवृत्ति को कैसे गिनें?शब्द आवृत्ति गणना जावा 8
List <String> = Lists.newArrayList("hello", "bye", "ciao", "bye", "ciao");
परिणाम होना चाहिए:
{ciao=2, hello=1, bye=2}
मैं समाधान मैं क्योंकि पहली बार में पाया मैं नक्शा और कम करने का उपयोग करने के तरीकों की उम्मीद साझा करना चाहते हैं, लेकिन यह थोड़ा अलग था।
Map<String, Long> collect =
wordsList.stream().collect(groupingBy(Function.identity(), counting()));
या पूर्णांक मूल्यों के लिए:
Map<String, Integer> collect =
wordsList.stream().collect(groupingBy(Function.identity(), summingInt(e -> 1)));
संपादित
मैं कैसे मान द्वारा नक्शा सॉर्ट करने के लिए जोड़ें:
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
));
(नोट: संपादन देखें से नीचे)
Mounas answer के लिए एक विकल्प के रूप में, यहाँ एक दृष्टिकोण है कि शब्द समानांतर में गिनती करता है:
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);
}
}
टिप्पणी के जवाब में संपादित करें, मैं JMH साथ एक छोटे से परीक्षण भाग गया,
toConcurrentMap
तुलना और विभिन्न इनपुट सूची आकार और विभिन्न लंबाई के यादृच्छिक शब्दों के साथgroupingByConcurrent
दृष्टिकोण। इस परीक्षण ने सुझाव दिया किtoConcurrentMap
दृष्टिकोण तेज था। विचार करते समय इन दृष्टिकोणों को "हुड के नीचे" कितना अलग है, इस तरह कुछ भविष्यवाणी करना मुश्किल है।आगे की टिप्पणियों के आधार पर आगे के विस्तार के रूप में, मैंने
toMap
,groupingBy
, सीरियल और समांतर के सभी चार संयोजनों को कवर करने के लिए परीक्षण बढ़ाया।परिणाम अभी भी (कम से कम मेरे लिए) कि
toMap
दृष्टिकोण तेजी से होता है, लेकिन अप्रत्याशित रूप से दोनों ही मामलों में "समवर्ती" संस्करण धारावाहिक संस्करणों की तुलना में धीमी कर रहे हैं ...:
(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
मैं इतना JMH के साथ अनुभव नहीं कर रहा हूँ, शायद मैं यहाँ कुछ गलत किया था - सुझाव और सुधार का स्वागत है:
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;
}
}
बार केवल 10000 तत्वों के साथ एक सूची के सीरियल मामले के लिए समान हैं, और 2-अक्षर वाले शब्द।
यह भी बड़ा सूची आकार के लिए जांच करने के लिए सार्थक हो सकता है, संगत संस्करणों अंत में धारावाहिक लोगों को मात, लेकिन वर्तमान में इन सभी विन्यास के साथ एक और विस्तृत बेंचमार्क रन के लिए समय नहीं है।
मुझे लगता है, 'संग्राहक.groupingByConcurrent (w-> w, संग्राहक.counting())' अधिक कुशल होगा। – Holger
@ होल्गर मैंने इस बारे में एक संपादन जोड़ा। – Marco13
आपको * बराबर * शब्दों की संख्या पर भी ध्यान देना चाहिए। एक मानचित्र प्रविष्टि के लिए विवाद का महत्वपूर्ण प्रभाव हो सकता है। हजारों अलग-अलग शब्दों की गणना करना जावा 8 के 'कंसूरेंटमैप' में किसी भी विवाद के बिना काम कर सकता है, हालांकि मैं '1' की गिनती को संग्रहित नहीं करता हूं। तो, एक ही शब्द की हजार घटनाओं की गिनती एक अलग तस्वीर दे सकती है ... – Holger
यदि आप Eclipse Collections का उपयोग करते हैं, तो आप List
को 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"));
यह कोड जावा 5 - 8 के साथ काम करेगा।
नोट: मैं ग्रहण संग्रह के लिए एक committer
मैं यहाँ समाधान जो मैंने बनाया पेश करेंगे हूँ (समूह के साथ एक बेहतर है :))।
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)));
}
बस मेरे 0.02 $
मुझे Collections.frequency (इनपुट, str) के बारे में पता था। आपके इनपुट के लिए धन्यवाद। – Sam
मेरा एक अन्य 2 प्रतिशत, एक सरणी दिया:
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)));
फ़्रीक्वेंसी मानचित्र मानचित्र कार्यों का उपयोग कर बनाने के लिए एक तरीका है।
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}
या
words.forEach(word ->
frequencyMap.compute(word, (k, v) -> v != null ? v + 1 : 1)
);
, संग्रह में सबसे लगातार आइटम खोजें जेनरिक के साथ:
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);
}
कंप्यूट आइटम आवृत्तियों:
private <V> Map<V, Long> findFrequencies(final Collection<V> items)
{
return items.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Functions.identity(), Collectors.counting()));
}
क्यों 'summingInt (ई -> 1) '? बस ['गिनती()'] (http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#counting--) का उपयोग करें। नतीजा एक 'नक्शा <स्ट्रिंग, लांग>' होगा लेकिन उसे चोट नहीं पहुंचीगी। Btw। आप 'e-> e' को 'function.identity()' से बदल सकते हैं (लेकिन आपको यह नहीं करना है)। – Holger