我有一个字符串数组:
String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};
按照每个Collection
频率与频率的频率顺序排列为String
的最快/最有效的方法是什么?
我虽然使用String
作为HashMap<String,Integer>
中的关键字,但这不会按频率排序
我考虑的其他方法是使用带有该整数的字符串列表的TreeMap<Integer, String[]>
,但似乎涉及很多检查..
我试图避免使用多个循环如果可能,因为我的String
数组将比上面的数组大得多。谢谢!
修改 我想要的只是能够按频率顺序输出字符串,并且最好能够将该字符串与其频率在数组中配对,例如两个输出数组:
["x", "y", "z", "a"]
[3,2,1,1]
如果速度不是问题,这将是一个非常简单的问题,这就是为什么我在这里问伟大的思想:)
答案 0 :(得分:10)
您可以分两步解决此问题:
创建一个计数器对象 - 每个字符串的Map<String, Integer>
列表,它在输入中出现的次数:换句话说,它是一个频率图。这是O(n)
,因为您只需要遍历输入一次以构建地图
使用上一个地图,创建一个包含其键的列表,使用项目的频率(地图中的值)作为排序标准进行排序。这是O(n log n)
,您可以使用Collections.sort()
来调用Comparator
,使用字符串频率进行比较
这就是我的意思:
String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};
final Map<String, Integer> counter = new HashMap<String, Integer>();
for (String str : stringArray)
counter.put(str, 1 + (counter.containsKey(str) ? counter.get(str) : 0));
List<String> list = new ArrayList<String>(counter.keySet());
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String x, String y) {
return counter.get(y) - counter.get(x);
}
});
执行上述代码后,变量list
将包含以下值(未指定相同频率的元素之间的顺序):
[x, y, a, z]
将列表转换为数组非常简单:
list.toArray(new String[list.size()])
如果你需要找出每个字符串的频率,只需遍历排序的键:
for (String str : list) {
int frequency = counter.get(str);
System.out.print(str + ":" + frequency + ", ");
}
答案 1 :(得分:3)
使用HashMap<String,Integer>
来维持您的计数。这将是处理任意字符串列表的最有效方法。
从地图ArrayList<Map.Entry<String,Integer>>
创建entrySet()
。
使用Collections.sort()
和自定义比较器对此列表进行排序。
不要挂在微优化上。
答案 2 :(得分:2)
如果第三方图书馆是公平的游戏,那么以下与番石榴的单行程是渐近最优的:
Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(array))
.elementSet().toArray(new String[0]);
答案 3 :(得分:1)
String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};
List<String> list = Arrays.asList(stringArray);
Collections.sort(list);
HashMap<String, Integer> map = new HashMap<String, Integer>();
for(int i = 0; i < list.size();) {
String s = list.get(i); //get the string to count
int count = list.lastIndexOf(s) - list.indexOf(s) + 1; //count it
map.put(s, count); // add it
i = list.lastIndexOf(s) + 1; // skip to the next string
}
我认为这是一个优雅的解决方案,但我不知道它是多么高效。 如果您对它进行了排序,请使用TreeMap,但这确实很慢。
您可以像这样对其进行排序:
TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>(unsortedMap);
但请注意,将Integer
作为键是行不通的!
因为一个键是唯一的,例如a和b出现一次,就会被踢掉!
答案 4 :(得分:1)
打印结果: 1)以desc顺序排序的具有不同出现的字符串。 2)具有相同出现的字符串按字符串按升序排序。
public static void sortStringByOccurance(String[] stringArray) {
// O(n)
Map<String, Integer> map = new HashMap<>();
for (String str : stringArray) {
map.put(str, map.containsKey(str)? map.get(str)+1 : 1);
}
// O(n)
TreeMap<Integer, TreeSet<String>> treemap = new TreeMap<>();
for (String key : map.keySet()) {
if (treemap.containsKey(map.get(key))) {
treemap.get(map.get(key)).add(key);
}
else {
TreeSet<String> set = new TreeSet<>();
set.add(key);
treemap.put(map.get(key), set);
}
}
// O(n)
Map<Integer, TreeSet<String>> result = treemap.descendingMap();
for (int count : result.keySet()) {
TreeSet<String> set = result.get(count);
for (String word : set) {
System.out.println(word + ":" + count);
}
}
}
答案 5 :(得分:0)
可以用最少的代码行:
String[] s = {"x", "y", "z", "x", "x", "y", "a"};
HashMap<String,Integer> hm = new HashMap<String,Integer>();
for(int i=0;i<s.length;i++){
int count = hm.containsKey(s[i]) ? hm.get(s[i]) : 0;
hm.put(s[i], count + 1);
}
答案 6 :(得分:0)
另一种解决方案:
String[] s = {"x", "y", "z", "x", "x", "y", "a"};
HashMap<String,Integer> hm = new HashMap<String,Integer>();
for(int i=0;i<s.length;i++){
hm.putIfAbsent(s[i], 0);
hm.put(s[i], hm.get(s[i]) + 1);
}
System.out.println(hm);