-2

我有一个查询,我开发了一张我想排序的地图,请告知..

  HashMap map=new HashMap();//HashMap key random order.
     map.put("Amit","Java");
     map.put("Saral","J2EE");
     map.put("ty","Spring");
     map.put("Anupam","Hibernate");
     map.put("Ravi",".Net");
     map.put("Saral","Andriod");//same key but different value 
     map.put("Nitin","PHP");
     map.put("hj","Spring1");
     System.out.println("There are "+map.size()+" elements in the map.");
     System.out.println("Content of Map are...");
     Set s=map.entrySet();
     Iterator itr=s.iterator();
     while(itr.hasNext())
     {
         Map.Entry m=(Map.Entry)itr.next();
         System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
      }
4

2 回答 2

4

如果您希望它按(字符串)键排序,那么只需使用java.util.TreeMap而不是HashMap.

于 2012-04-17T16:41:44.483 回答
0

有一些事情需要考虑,它们会影响您真正想要的解决方案。

您正在使用 a ,这意味着您需要 a -typeHashMap<K, V>的关联和键查找行为。Map

HashMap它本身并不关心排序 - 每当您插入键值对时,hashCode()都会调用键的方法,并且映射使用该哈希码存储配对。String对象已经有了正确的hashCode()实现,因此您可以毫无问题地将它们用作键。

当然,在检索或迭代您HashMap的 .

由于您想“排序”您的数据,我假设您的意思是您希望您的配对返回,按键排序(按您输入的名称排序)。

现在这里是需要考虑的地方:

保持数据始终排序

如果您希望始终对数据进行排序,即每次插入新的键值对时,都希望保持元素的自然顺序,那么您可以使用 Java API 中的一些方便的数据结构:

使用TreeMap

正如 Dilum 已经提到的,您可以使用java.util.TreeMap实现java.util.SortedMap接口的 ,这将保证对映射中的键进行排序。

例子:

import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class SortedMapExample {
    public static void main(String[] args) {
        SortedMap<String, String> map = new TreeMap<String, String>();
        map.put("Amit","Java");
        map.put("Saral","J2EE");
        map.put("ty","Spring");
        map.put("Anupam","Hibernate");
        map.put("Ravi",".Net");
        map.put("Saral","Andriod");//same key but different value 
        map.put("Nitin","PHP");
        map.put("hj","Spring1");

        for (Map.Entry<String, String> e : map) {
            System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
        }
    }
}

如果您运行此代码,您将得到它:

λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring

使用ConcurrentSkipListMap

ConcurrentSkipListMap是一种较新的数据结构,首先在 Java 6 中可用。它还实现了SortedMap接口,底层实现涉及跳过列表

它也是一个并发集合,您可以在Brian Goetz 的这篇文章中了解更多信息。简而言之, Java 并发集合java.util.concurrent是高性能的线程安全集合。

将前面的示例更改为使用ConcurrentSkipListMap.

import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap; // this changed

public class SortedMapExample {
    public static void main(String[] args) {
        // the following line changed - now you know the power of programming to interfaces
        SortedMap<String, String> map = new ConcurrentSkipListMap<String, String>();
        map.put("Amit","Java");
        map.put("Saral","J2EE");
        map.put("ty","Spring");
        map.put("Anupam","Hibernate");
        map.put("Ravi",".Net");
        map.put("Saral","Andriod");//same key but different value 
        map.put("Nitin","PHP");
        map.put("hj","Spring1");

        for (Map.Entry<String, String> e : map) {
            System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
        }
    }
}

运行此代码,您将获得完全相同的输出:

λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring

按需排序

也许在您的用例中,您不希望始终保持数据排序。也许这是一个性能问题(如果这是您关心的问题,请进行基准测试),并且您实际上只需要在请求时对数据进行排序。

在您的情况下,您可以在Collections.sort数据键上使用。

坚持你的HashMap例子:

import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

public class UnsortedExample {
   public static void main(String[] args) {
      Map<String, String> map = new HashMap<String, String>();
      map.put("Amit", "Java");
      map.put("Saral","J2EE");
      map.put("ty","Spring");
      map.put("Anupam","Hibernate");
      map.put("Ravi",".Net");
      map.put("Saral","Andriod");//same key but different value
      map.put("Nitin","PHP");
      map.put("hj","Spring1");

      List<String> keys = new ArrayList<String>(map.keySet());
      Collections.sort(keys);

      for (String key : keys) {
          System.out.println(String.format("%s - %s", key, map.get(key)));
      }
   }
}

在这里,我keySet()从地图中提取了 ,它返回了一个Set包含地图中所有键的对象。然后我把它变成一个ArrayList并排序列表,然后遍历列表并将值从地图中提取出来。

java.util.TreeSet拔出来的时候也可以用keySet(),和和TreeSet自然一样是有序TreeMapConcurrentSkipListMap

使用示例SortedSet

java.util.SortedSet<String> keys = new java.util.TreeSet<String>(map.keySet());

顺便说一句,还有一个java.util.concurrent.ConcurrentHashMap类,它是 Java Concurrency 版本,java.util.HashMap并且在将发生并发访问的多线程环境中运行良好。

哇哇,为什么排序很奇怪?

此示例使用英语(我对“排序”的非英语语言了解不多),但您可以看到排序有些奇怪。

例如,在前面示例的输出中,"hj"出现在 之后"Saral",而人类可能会真正按字母顺序排列列表,例如"hj"介于"Anupam"和之间"Nitin"

默认情况下,java.lang.String实现Comparable接口,定义自然排序。Java 与几乎所有其他正在使用的编程语言一样,将大写英文字母排在小写字母之前。

简单的解释是,在 ASCII/UTF-8 中,英文大写字母排在英文小写字母之前。

但是,您可能需要忽略大小写的不同字母排序。为此,您必须编写自己的实现类Comparator,并将其传递给 or 的构造函数,TreeMap或传递ConcurrentSkipListMapCollections.sort采用比较器对象的方法。

如果你想实现这样的排序,我会把它作为练习留给你。

结论

从表面上看,您的问题只是对您的Map-like 对象中的数据进行排序。

您可以选择使用:

  • java.util.TreeMap- 按自然顺序保持元素排序
  • java.util.concurrent.ConcurrentSkipListMap- 与上面相同,但具有良好的线程安全性
  • 使用按需排序Collections.sort()

我不知道你对这个数据结构有什么用,或者它在什么环境中使用。例如,如果你的 有多线程访问HashMap,那么你需要同步机制,而同步机制HashMap本身没有。为此,它更容易使用java.util.concurrent.ConcurrentSkipListMapor java.util.concurrent.ConcurrentHashmap

因此,根据您使用数据的方式,有不同的方法可以对数据进行排序。如果您想要始终排序,那么我建议您使用ConcurrentSkipListMap(for multithreaded) 或TreeMap. 如果您需要HashMap分期 O(1) 的插入性能,那么您可能需要使用HashMap和排序“按需”方式,或者保留一个单独的数据结构来排序您的键。如果您对特定用途有性能问题,请进行分析。

还有一些额外的细节:

  • 我正在使用每个循环来遍历我上面的数据结构。如果您只需要元素访问(而不是突变/删除),那么 for-each 是显式迭代器的非常好的语法糖。
  • 在我的示例中,我使用接口作为变量的类型,而不是具体的类(在您的代码中,HashMap<...> map = new HashMap<...>();.
于 2012-04-17T21:52:23.760 回答