我需要写一个循环来统计字符串中每个字母的出现频率。
例如:"aasjjikkk" 将会有 2 个 'a',1 个 's',2 个 'j',1 个 'i',3 个 'k'。最终,我希望这些数据以字母为键、出现次数为值的形式被存储在一个 map 中。有好的想法如何实现吗?
例如:
Map<Character, Integer> map = new HashMap<Character, Integer>();
String s = "aasjjikkk";
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
Integer val = map.get(c);
if (val != null) {
map.put(c, val + 1);
}
else {
map.put(c, 1);
}
}
最终,您将拥有遇到的所有字符计数,并可以从中提取它们的频率。
或者,您可以使用Bozho的解决方案,使用Multiset并计算总出现次数。
Map<Character, Long> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map<Character, Integer> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(c -> 1)));
Map<Character, Integer> frequency =
str.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.toMap(Function.identity(), c -> 1, Math::addExact));
一个简洁的方法是:
Map<Character,Integer> frequencies = new HashMap<>();
for (char ch : input.toCharArray())
frequencies.put(ch, frequencies.getOrDefault(ch, 0) + 1);
我们使用for-each循环遍历每个字符。 frequencies.getOrDefault()
如果键存在,则获取其值,否则返回(默认情况下)第二个参数。
frequencies.merge(ch, 1, Integer::sum);
这样也不需要进行两次地图查找。 - undefined这里有另一个方案,虽然可能不太可靠。
public char getNumChar(String s) {
char[] c = s.toCharArray();
String alphabet = "abcdefghijklmnopqrstuvwxyz";
int[] countArray = new int[26];
for (char x : c) {
for (int i = 0; i < alphabet.length(); i++) {
if (alphabet.charAt(i) == x) {
countArray[i]++;
}
}
}
java.util.HashMap<Integer, Character> countList = new java.util.HashMap<Integer, Character>();
for (int i = 0; i < 26; i++) {
countList.put(countArray[i], alphabet.charAt(i));
}
java.util.Arrays.sort(countArray);
int max = countArray[25];
return countList.get(max);
}
countArray[i - 'a']++;
。而且,为了找到数组的最大值而进行排序是相当低效的。你可以通过一个简单的线性循环找到最大值,并且在这样做的同时,你也知道它的索引对应的字母,使得HashMap
变得不再必要。 - undefined因为没有Java 8的解决方案,所以考虑发布一个。此外,这个解决方案比其他一些提到的解决方案更加整洁、可读、简洁。
String string = "aasjjikkk";
Map<Character, Long> characterFrequency = string.chars() // creates an IntStream
.mapToObj(c -> (char) c) // converts the IntStream to Stream<Character>
.collect(Collectors.groupingBy(c -> c, Collectors.counting())); // creates a
// Map<Character, Long>
// where the Long is
// the frequency
for(int i = 0; i < str.length; i ++)
freq[str[i] - 'a'] ++; //假设所有字符都是小写
这里有一个解决方案:
定义您自己的 Pair
:
public class Pair
{
private char letter;
private int count;
public Pair(char letter, int count)
{
this.letter = letter;
this.count= count;
}
public char getLetter(){return key;}
public int getCount(){return count;}
}
那么你可以这样做:
public static Pair countCharFreq(String s)
{
String temp = s;
java.util.List<Pair> list = new java.util.ArrayList<Pair>();
while(temp.length() != 0)
{
list.add(new Pair(temp.charAt(0), countOccurrences(temp, temp.charAt(0))));
temp.replaceAll("[" + temp.charAt(0) +"]","");
}
}
public static int countOccurrences(String s, char c)
{
int count = 0;
for(int i = 0; i < s.length(); i++)
{
if(s.charAt(i) == c) count++;
}
return count;
}
您可以使用来自Eclipse Collections的CharAdapter
和CharBag
,避免将数据装箱为Character
和Integer
。
CharBag bag = Strings.asChars("aasjjikkk").toBag();
Assert.assertEquals(2, bag.occurrencesOf('a'));
Assert.assertEquals(1, bag.occurrencesOf('s'));
Assert.assertEquals(2, bag.occurrencesOf('j'));
Assert.assertEquals(1, bag.occurrencesOf('i'));
Assert.assertEquals(3, bag.occurrencesOf('k'));
String s = "aaaabbbbcccddddd";
Map<Character, Integer> map = new HashMap<>();
s.chars().forEach(e->map.put((char)e, map.getOrDefault((char)e, 0) + 1));