按值对元素排序的数据结构
Data Structure to sort elements by values
我需要 Java 中的数据结构,它可以操作 String
s,计算 ArrayList<String>
中每个单词的频率,然后我需要根据频率对它们进行排序.
简单来说,数据结构需要是一个关联数组,可以BY VALUES排序,我已经把行进入 HashMap
并且对 它无法排序的事实感到惊讶 ,现在我一直在思考另一个数据结构。
P.S。 (使用两个列表不适合我的程序,因为它需要进行大量计算,所以如果单个结构包含每个 String
及其出现而不是 String
的列表会更好s 和另一个频率)。
编辑:感谢您的帮助,但有些人建议 TreeMap
,所以我想在这里指定一些内容:我需要按字符串的出现排序的结构(在 [= 的情况下) 16=]s 它将是值而不是键)。
Java 有一个 SortedMap interface with two implementations. The easiest one being TreeMap
HashMap
没有排序,实际上也不应该这样。如果您想对条目进行排序,您可以使用 SortedMap
实现之一,例如 TreeMap
.
TreeMap
有一个构造函数,如果您有非标准的 Comparator
(例如,如果您想要 String
s 的自然排序),它可以帮助您:
TreeMap(Comparator<? super K> comparator)
UPD:我错过了重点,您需要按值对条目进行排序。
在这种情况下,我看不到任何解决方案,除了一个,在该解决方案中,您只需对条目进行多次排序,而不是保持这种状态。
您可以使用任何 Map
,例如,留在 HashMap
,但是在处理之前,您可以对条目进行排序:
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Set<Map.Entry<String, Integer>> sorted = new TreeSet<>(
Comparator.comparingInt(Map.Entry::getValue).reversed()); // it's Java 8, but you may extract this lambda
sorted.addAll(entries);
for (Map.Entry<String, Integer> entry: sorted) {
//...
// the entries will be sorted by value
}
准确地说,您不能使用任何类型的 Map
来维护以这种方式排序的条目,因为键的顺序只设置一次并且您无法更改它,因为:
- 这不是传统的,
Comparator
/compareTo
运算符应该给出与 运行 相同的结果(这就是为什么可变 类 在 Map
s)
- 预计这不会给您一些明显的结果,通常不会对键重新排序。
另一种解决方案,使用自定义 bean 和简单列表。
1/ 定义您的自定义 bean
public class StringOccurence {
String string ;
int occurrence ;
}
2/ 创建比较器
public class StringOccurrenceComparator implements Comparator<StringOccurence> {
@Override
public int compare(StringOccurrence so1, StringOccurrence so2) {
return Integer.compare(so1.occurrence, so2.occurrence);
}
}
3/ 使用比较器对列表进行排序
List<StringOccurrence> list = constructList();
Collections.sort(list, new StringOccurrenceComparator());
如果你有幸使用 java8,这里是第 2 点和第 3 点的简短版本:
List<StringOccurrence> list = constructList();
Collections.sort(list, (so1, so2) -> Integer.compare(so1.occurrence, so2.occurrence));
我认为这没有简单的数据结构。
当您收集频率数据时,频率正在发生变化。收集所有字符串频率后应该对哪个进行排序。
我能想到的最简单的方法是:
// psuedo-code
final Map<String, Integer> stringFreq = ....; // it doesn't matter what kind of impl you use
// collect the String vs frequency in stringFreq
Map<String, Integer> result = new TreeMap<String, Integer>(stringFreq,
new Comparator<String> {
@Override
public int compare(String a, String b) {
int aFreq = stringFreq.get(a);
int bFreq = stringFreq.get(b);
return (aFreq==bFreq)?a.compareTo(b) : (aFreq-bFreq);
}
});
// result should have data sorted by frequency, and then the string value
如果你用一个maxheap数据结构来存储字符串和它的出现频率值,并且始终保持最大值频率在最前面,那么你可以简单地一次性获得频率最大的那个,但是这里的复杂性是重新计算和调整最大堆,因此实际上取决于您希望看到更多的变化类型 - 更多的单词数量或高度变化的单词频率。
我需要 Java 中的数据结构,它可以操作 String
s,计算 ArrayList<String>
中每个单词的频率,然后我需要根据频率对它们进行排序.
简单来说,数据结构需要是一个关联数组,可以BY VALUES排序,我已经把行进入 HashMap
并且对 它无法排序的事实感到惊讶 ,现在我一直在思考另一个数据结构。
P.S。 (使用两个列表不适合我的程序,因为它需要进行大量计算,所以如果单个结构包含每个 String
及其出现而不是 String
的列表会更好s 和另一个频率)。
编辑:感谢您的帮助,但有些人建议 TreeMap
,所以我想在这里指定一些内容:我需要按字符串的出现排序的结构(在 [= 的情况下) 16=]s 它将是值而不是键)。
Java 有一个 SortedMap interface with two implementations. The easiest one being TreeMap
HashMap
没有排序,实际上也不应该这样。如果您想对条目进行排序,您可以使用 SortedMap
实现之一,例如 TreeMap
.
TreeMap
有一个构造函数,如果您有非标准的 Comparator
(例如,如果您想要 String
s 的自然排序),它可以帮助您:
TreeMap(Comparator<? super K> comparator)
UPD:我错过了重点,您需要按值对条目进行排序。
在这种情况下,我看不到任何解决方案,除了一个,在该解决方案中,您只需对条目进行多次排序,而不是保持这种状态。
您可以使用任何 Map
,例如,留在 HashMap
,但是在处理之前,您可以对条目进行排序:
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Set<Map.Entry<String, Integer>> sorted = new TreeSet<>(
Comparator.comparingInt(Map.Entry::getValue).reversed()); // it's Java 8, but you may extract this lambda
sorted.addAll(entries);
for (Map.Entry<String, Integer> entry: sorted) {
//...
// the entries will be sorted by value
}
准确地说,您不能使用任何类型的 Map
来维护以这种方式排序的条目,因为键的顺序只设置一次并且您无法更改它,因为:
- 这不是传统的,
Comparator
/compareTo
运算符应该给出与 运行 相同的结果(这就是为什么可变 类 在Map
s) - 预计这不会给您一些明显的结果,通常不会对键重新排序。
另一种解决方案,使用自定义 bean 和简单列表。
1/ 定义您的自定义 bean
public class StringOccurence {
String string ;
int occurrence ;
}
2/ 创建比较器
public class StringOccurrenceComparator implements Comparator<StringOccurence> {
@Override
public int compare(StringOccurrence so1, StringOccurrence so2) {
return Integer.compare(so1.occurrence, so2.occurrence);
}
}
3/ 使用比较器对列表进行排序
List<StringOccurrence> list = constructList();
Collections.sort(list, new StringOccurrenceComparator());
如果你有幸使用 java8,这里是第 2 点和第 3 点的简短版本:
List<StringOccurrence> list = constructList();
Collections.sort(list, (so1, so2) -> Integer.compare(so1.occurrence, so2.occurrence));
我认为这没有简单的数据结构。
当您收集频率数据时,频率正在发生变化。收集所有字符串频率后应该对哪个进行排序。
我能想到的最简单的方法是:
// psuedo-code
final Map<String, Integer> stringFreq = ....; // it doesn't matter what kind of impl you use
// collect the String vs frequency in stringFreq
Map<String, Integer> result = new TreeMap<String, Integer>(stringFreq,
new Comparator<String> {
@Override
public int compare(String a, String b) {
int aFreq = stringFreq.get(a);
int bFreq = stringFreq.get(b);
return (aFreq==bFreq)?a.compareTo(b) : (aFreq-bFreq);
}
});
// result should have data sorted by frequency, and then the string value
如果你用一个maxheap数据结构来存储字符串和它的出现频率值,并且始终保持最大值频率在最前面,那么你可以简单地一次性获得频率最大的那个,但是这里的复杂性是重新计算和调整最大堆,因此实际上取决于您希望看到更多的变化类型 - 更多的单词数量或高度变化的单词频率。