Java Class yang mengimplementasikan Map dan menjaga urutan penyisipan?

463

Saya mencari kelas di java yang memiliki asosiasi nilai kunci, tetapi tanpa menggunakan hash. Inilah yang sedang saya lakukan:

  1. Tambahkan nilai ke a Hashtable.
  2. Dapatkan iterator untuk Hashtable.entrySet().
  3. Ulangi semua nilai dan:
    1. Dapatkan Map.Entryuntuk iterator.
    2. Buat objek tipe Module(kelas kustom) berdasarkan nilai.
    3. Tambahkan kelas ke JPanel.
  4. Tampilkan panel.

Masalah dengan ini adalah bahwa saya tidak memiliki kontrol atas urutan yang saya dapatkan kembali nilai-nilai, jadi saya tidak dapat menampilkan nilai-nilai dalam urutan yang diberikan (tanpa hard-coding urutan).

Saya akan menggunakan ArrayListatau Vectoruntuk ini, tetapi nanti dalam kode saya perlu mengambil Moduleobjek untuk Kunci yang diberikan, yang saya tidak bisa lakukan dengan ArrayListatau Vector.

Apakah ada yang tahu tentang kelas Java sumber bebas / terbuka yang akan melakukan ini, atau cara untuk mendapatkan nilai Hashtableberdasarkan ketika mereka ditambahkan?

Terima kasih!

Shane
sumber
1
Anda tidak perlu menggunakan entryset / map.entry. Anda dapat mengulangi kunci dan nilai dengan menggunakan hashtable.keys sebagai enumerasi atau dengan menggunakan hashtable.keyset.iterator.
John Gardner
5
Saya mengambil kebebasan untuk mengubah judul, karena tidak menggunakan hash sebenarnya bukan masalah, tetapi menjaga urutan penyisipan.
Joachim Sauer
Pertanyaan Serupa, Java Ordered Map
Basil Bourque

Jawaban:

734

Saya sarankan a LinkedHashMapatau a TreeMap. A LinkedHashMapmenyimpan kunci dalam urutan yang dimasukkan, sementara TreeMapdisimpan diurutkan melalui Comparatoratau urutan alami Comparableelemen.

Karena tidak harus menjaga elemen diurutkan, LinkedHashMapharus lebih cepat untuk sebagian besar kasus; TreeMapmemiliki O(log n)kinerja untuk containsKey, get, put, dan remove, menurut Javadocs, sedangkan LinkedHashMapadalah O(1)untuk setiap.

Jika API Anda yang hanya mengharapkan urutan pengurutan yang dapat diprediksi, sebagai lawan dari urutan pengurutan tertentu, pertimbangkan untuk menggunakan antarmuka yang diterapkan oleh dua kelas ini, NavigableMapatau SortedMap. Ini akan memungkinkan Anda untuk tidak membocorkan implementasi spesifik ke dalam API Anda dan beralih ke salah satu dari kelas spesifik tersebut atau implementasi yang sama sekali berbeda setelahnya.

Michael Myers
sumber
2
Ini tidak akan berfungsi untuk saya karena, sesuai javadocs, ini hanya memberikan nilai yang dipesan (melalui panggilan nilai ()). Apakah ada cara untuk memesan Map.Entry instance?
Cory Kendall
1
@CoryKendall: Apakah TreeMap tidak berfungsi? Seharusnya diurutkan berdasarkan kunci, bukan oleh nilai.
Michael Myers
1
Kesalahan saya, saya pikir Sets tidak disortir.
Cory Kendall
61
Harap dicatat: Penyortiran TreeMap didasarkan pada urutan alami kunci: "Peta diurutkan sesuai dengan urutan alami kunci-kuncinya". LinkedHashMap diurutkan berdasarkan urutan penyisipan. Perbedaan besar!
Jop van Raaij
3
@AlexR: Itu hanya benar jika LinkedHashMap dibuat menggunakan konstruktor khusus yang disediakan untuk tujuan itu. Secara default, iterasi dalam urutan penyisipan.
Michael Myers
22

LinkedHashMap akan mengembalikan elemen dalam urutan mereka dimasukkan ke dalam peta ketika Anda mengulangi keySet (), entrySet () atau nilai () peta.

Map<String, String> map = new LinkedHashMap<String, String>();

map.put("id", "1");
map.put("name", "rohan");
map.put("age", "26");

for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}

Ini akan mencetak elemen sesuai urutan mereka dimasukkan ke dalam peta:

id = 1
name = rohan 
age = 26 
Praveen Kishor
sumber
16

Jika peta yang tidak berubah sesuai dengan kebutuhan Anda, maka ada perpustakaan oleh google bernama jambu (lihat juga pertanyaan jambu )

Guava menyediakan ImmutableMap dengan pesanan iterasi yang ditentukan pengguna yang andal. ImmutableMap ini memiliki kinerja O (1) untuk containKey, dapatkan. Jelas menempatkan dan menghapus tidak didukung.

Objek ImmutableMap dibuat dengan menggunakan metode kenyamanan statis statis () dan copyOf () atau objek Builder .

jvdneste
sumber
6

Anda dapat mempertahankan Map(untuk pencarian cepat) dan List(untuk pesanan) tetapi LinkedHashMapmungkin yang paling sederhana. Anda juga dapat mencoba SortedMapmisalnya TreeMap, yang memiliki pesanan apa pun yang Anda tentukan.

Peter Lawrey
sumber
1

Saya tidak tahu apakah itu opensource, tetapi setelah sedikit googling, saya menemukan implementasi Peta ini menggunakan ArrayList . Sepertinya Java pra-1.5, jadi Anda mungkin ingin membuatnya generik, yang seharusnya mudah. Perhatikan bahwa implementasi ini memiliki akses O (N), tetapi ini seharusnya tidak menjadi masalah jika Anda tidak menambahkan ratusan widget ke JPanel Anda, yang toh tidak seharusnya Anda lakukan.

jpalecek
sumber
1

Setiap kali saya perlu mempertahankan urutan alami dari hal-hal yang diketahui sebelumnya, saya menggunakan EnumMap

kunci akan enum dan Anda dapat memasukkan dalam urutan apa pun yang Anda inginkan tetapi ketika Anda mengulanginya akan beralih dalam urutan enum (urutan alami).

Juga ketika menggunakan EnumMap seharusnya tidak ada tabrakan yang bisa lebih efisien.

Saya benar-benar menemukan bahwa menggunakan enumMap membuat kode yang mudah dibaca bersih. Berikut ini sebuah contoh

j2emanue
sumber
1

Anda dapat menggunakan LinkedHashMap untuk urutan penyisipan utama di Peta

Poin penting tentang kelas Java LinkedHashMap adalah:

  1. Ini hanya mengandung elemen unik.
  2. LinkedHashMap berisi nilai berdasarkan kunci 3. Mungkin memiliki satu kunci nol dan beberapa nilai nol. 4. Ini sama dengan HashMap sebagai gantinya mempertahankan urutan penyisipan

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 

Tetapi jika Anda ingin mengurutkan nilai di peta menggunakan objek yang ditentukan Pengguna atau kunci tipe data primitif apa pun maka Anda harus menggunakan TreeMap Untuk informasi lebih lanjut, lihat tautan ini

Pankaj Goyal
sumber
0

Baik Anda dapat menggunakan LinkedHashMap<K, V>atau Anda dapat menerapkan CustomMap Anda sendiri yang mempertahankan urutan penyisipan.

Anda dapat menggunakan Berikut CustomHashMapdengan fitur-fitur berikut:

  • Urutan penyisipan dipertahankan, dengan menggunakan LinkedHashMap secara internal.
  • Kunci dengan nullatau string kosong tidak diizinkan.
  • Setelah kunci dengan nilai dibuat, kami tidak mengganti nilainya.

HashMapvs LinkedHashMapvsCustomHashMap

interface CustomMap<K, V> extends Map<K, V> {
    public boolean insertionRule(K key, V value);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CustomHashMap<K, V> implements CustomMap<K, V> {
    private Map<K, V> entryMap;
    // SET: Adds the specified element to this set if it is not already present.
    private Set<K> entrySet;

    public CustomHashMap() {
        super();
        entryMap = new LinkedHashMap<K, V>();
        entrySet = new HashSet();
    }

    @Override
    public boolean insertionRule(K key, V value) {
        // KEY as null and EMPTY String is not allowed.
        if (key == null || (key instanceof String && ((String) key).trim().equals("") ) ) {
            return false;
        }

        // If key already available then, we are not overriding its value.
        if (entrySet.contains(key)) { // Then override its value, but we are not allowing
            return false;
        } else { // Add the entry
            entrySet.add(key);
            entryMap.put(key, value);
            return true;
        }
    }
    public V put(K key, V value) {
        V oldValue = entryMap.get(key);
        insertionRule(key, value);
        return oldValue;
    }
    public void putAll(Map<? extends K, ? extends V> t) {
        for (Iterator i = t.keySet().iterator(); i.hasNext();) {
            K key = (K) i.next();
            insertionRule(key, t.get(key));
        }
    }

    public void clear() {
        entryMap.clear();
        entrySet.clear();
    }
    public boolean containsKey(Object key) {
        return entryMap.containsKey(key);
    }
    public boolean containsValue(Object value) {
        return entryMap.containsValue(value);
    }
    public Set entrySet() {
        return entryMap.entrySet();
    }
    public boolean equals(Object o) {
        return entryMap.equals(o);
    }
    public V get(Object key) {
        return entryMap.get(key);
    }
    public int hashCode() {
        return entryMap.hashCode();
    }
    public boolean isEmpty() {
        return entryMap.isEmpty();
    }
    public Set keySet() {
        return entrySet;
    }
    public V remove(Object key) {
        entrySet.remove(key);
        return entryMap.remove(key);
    }
    public int size() {
        return entryMap.size();
    }
    public Collection values() {
        return entryMap.values();
    }
}

Penggunaan CustomHashMap:

public static void main(String[] args) {
    System.out.println("== LinkedHashMap ==");
    Map<Object, String> map2 = new LinkedHashMap<Object, String>();
    addData(map2);

    System.out.println("== CustomHashMap ==");
    Map<Object, String> map = new CustomHashMap<Object, String>();
    addData(map);
}
public static void addData(Map<Object, String> map) {
    map.put(null, "1");
    map.put("name", "Yash");
    map.put("1", "1 - Str");
    map.put("1", "2 - Str"); // Overriding value
    map.put("", "1"); // Empty String
    map.put(" ", "1"); // Empty String
    map.put(1, "Int");
    map.put(null, "2"); // Null

    for (Map.Entry<Object, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
}

O / P:

== LinkedHashMap == | == CustomHashMap ==
null = 2            | name = Yash
name = Yash         | 1 = 1 - Str
1 = 2 - Str         | 1 = Int
 = 1                |
  = 1               |
1 = Int             |

Jika Anda tahu Kuncinya sudah diperbaiki maka Anda dapat menggunakan EnumMap. Dapatkan nilai dari Properties / file XML

EX:

enum ORACLE {
    IP, URL, USER_NAME, PASSWORD, DB_Name;
}

EnumMap<ORACLE, String> props = new EnumMap<ORACLE, String>(ORACLE.class);
props.put(ORACLE.IP, "127.0.0.1");
props.put(ORACLE.URL, "...");
props.put(ORACLE.USER_NAME, "Scott");
props.put(ORACLE.PASSWORD, "Tiget");
props.put(ORACLE.DB_Name, "MyDB");
Yash
sumber