【问题标题】:Data Structure to sort elements by values按值对元素进行排序的数据结构
【发布时间】:2015-08-09 05:35:10
【问题描述】:

我需要一个 Java 数据结构,它可以操作 Strings,计算 ArrayList<String> 中每个单词的频率,然后我需要根据频率对它们进行排序。

简单地说,数据结构需要是一个关联数组,可以BY VALUES排序,我已经把行放到HashMap无法排序令我感到惊讶,现在我一直在思考另一种数据结构。

附: (使用两个列表不适合我的程序,因为它需要进行大量计算,因此如果单个结构包含每个 String 及其出现而不是 Strings 的列表和另一个频率)。

编辑:感谢您的帮助,但有些人建议使用 TreeMap,所以我想在这里指定一些内容:我需要按字符串出现次数排序的结构(在 Maps 的情况下,它会是值而不是键)。

【问题讨论】:

  • 使用 TreeMap 代替 HashMap
  • 好吧,恕我直言,OP 非常清楚地给出了这个问题:他想要一个关联数组,其中 String 为键,频率为值,它将根据频率进行排序。实际上对我来说很有趣
  • @hemena314 我的代码使用了一个无法排序的哈希映射,这就是我没有显示它的原因,我想我已经很清楚我想要做什么了(计算出现次数字符串,然后根据出现的次数进行排序)
  • @hamena 我只需要一个可以排序的数据结构的指导......而且我不是只想在这里为他完成工作的人,我不需要编程指导,因为我的问题是概念性的......但无论如何谢谢
  • 谁说hashmap不能排序?

标签: java sorting data-structures associative-array


【解决方案1】:

Java 有一个带有两个实现的SortedMap 接口。最简单的是TreeMap

【讨论】:

  • 请再次阅读 OP 的要求:TreeMap 将根据键进行排序,但 OP 要求根据值(频率)进行排序
  • 问题中未指定。频率可能是关键?
  • 问题中提到了。请仔细阅读:)compute the frequency of each word in an ArrayList(of Strings) and then i need to sort it based on the frequencies。使用频率作为键也不行(原因很明显)
  • sharonbon,感谢您的帮助,但我担心 Adrian Shum 明白我在说什么,我需要可以按值排序的等效于 HashMap 的东西。
  • 现在,您编辑了您的问题,它更加清晰。不要惊讶为什么它以前的形式被否决了
【解决方案2】:

HashMap 没有排序,实际上不应该这样。如果要对条目进行排序,可以使用SortedMap 实现之一,例如TreeMap

TreeMap 有一个构造函数,如果你有非标准的Comparator(例如,如果你想对Strings 进行自然排序),它可以帮助你:

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 来维护以这种方式排序的条目,因为键的顺序只设置一次并且您无法更改它,因为:

  1. 这是非常规的,Comparator/compareTo 运算符在运行时应该给出相同的结果(这就是为什么在 Maps 中不支持可变类的原因)
  2. 预计这不会给您带来一些明显的结果,键通常不会重新排序。

【讨论】:

  • 比 LinkedHashMap 更好的解决方案
  • 请再次阅读 OP 要求的内容:TreeMap 将根据键进行排序,但 OP 要求根据值(频率)进行排序
【解决方案3】:

另一种解决方案,使用自定义 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));

【讨论】:

  • bean 被称为 StringOccurence 但 Comparator 和 List 泛型类型是 StringFrequency
  • @sharonbn 我真的需要更多的咖啡...谢谢 ;)
【解决方案4】:

我不认为有一个简单的数据结构。

当您收集频率数据时,频率会发生变化。在收集所有字符串频率之后应该进行哪些排序。

我能想到的最简单的方法是:

// 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

【讨论】:

    【解决方案5】:

    如果你使用一个maxheap数据结构来存储字符串及其出现频率的值,并且始终保持最大值频率在顶部,那么你可以简单地一次性得到频率最大的那个,但是复杂度这里将重新计算和调整最大堆,所以实际上取决于您希望看到什么样的变化——更多的词或词的高度变化的频率。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-31
      • 1970-01-01
      • 2011-05-24
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 2011-02-23
      • 2021-02-04
      相关资源
      最近更新 更多