Java Ordered Map

322

Di Jawa, Apakah ada objek yang bertindak seperti Peta untuk menyimpan dan mengakses pasangan kunci / nilai, tetapi dapat mengembalikan daftar kunci yang diurutkan dan daftar nilai yang diurutkan, sedemikian rupa sehingga daftar kunci dan nilai berada dalam urutan yang sama?

Jadi sebagai penjelasan-oleh-kode, saya mencari sesuatu yang berperilaku seperti OrderedMap fiktif saya:

OrderedMap<Integer, String> om = new OrderedMap<>();
om.put(0, "Zero");
om.put(7, "Seven");

String o = om.get(7); // o is "Seven"
List<Integer> keys = om.getKeys();
List<String> values = om.getValues();

for(int i = 0; i < keys.size(); i++)
{
    Integer key = keys.get(i);
    String value = values.get(i);
    Assert(om.get(key) == value);
}
Whatsit
sumber
4
Jika semua yang ingin Anda lakukan adalah mengulangi keduanya sekaligus, maka Map.entrySet () akan memungkinkan Anda melakukannya di peta mana pun. LinkedHashMap memiliki urutan yang jelas, tetapi untuk Peta apa pun set entri mencerminkan pasangan kunci / nilai.
Pete Kirkham
5
Kode ini bukan contoh yang baik karena implementasi Peta akan berlaku sebagai kode sampel Anda. disortir, dipesan atau tidak.
Peter Lawrey
2
Dalam implementasi Sun JDK, set yang dikembalikan oleh getKeys dan getValues ​​() set didukung oleh entrySet () di peta, jadi akan memiliki urutan iterasi yang sama, yang merupakan pengujian sampel Anda.
Pete Kirkham
4
Nah itu menarik, saya tidak pernah memperhatikannya. Tetap saja, panggil saya gila, tapi saya lebih suka tidak membuat asumsi tentang implementasi yang tidak secara eksplisit diverifikasi oleh antarmuka. Saya sudah terlalu sering terbakar melakukan itu di masa lalu.
Whatsit
2
Ini harus dinamai Java Sorted Map, karena Maped Order adalah sesuatu yang berbeda - lihat LinkedHashMap.
Ondra Žižka

Jawaban:

398

The SortedMap antarmuka (dengan pelaksanaan TreeMap ) harus menjadi teman Anda.

Antarmuka memiliki metode:

  • keySet() yang mengembalikan satu set kunci dalam urutan menaik
  • values() yang mengembalikan koleksi semua nilai dalam urutan menaik dari kunci yang sesuai

Jadi antarmuka ini memenuhi kebutuhan Anda. Namun, kunci harus memiliki urutan yang berarti. Kalau tidak, Anda dapat menggunakan LinkedHashMap di mana pesanan ditentukan oleh urutan penyisipan.

tuan
sumber
2
contoh: SortedMap <String, Object> map = new TreeMap <> ();
Ben
7
Untuk menggunakan TreeMap, diperlukan kelas kunci untuk mengimplementasikan antarmuka Sebanding. Jika tidak, maka beberapa jenis RuntimeException akan dibuang. TreeMap juga memetakan peta, tapi saya pikir penulis ingin menggunakan peta yang baru saja dipesan (tidak diurutkan). LinkedHashMap adalah pilihan yang baik untuk mendapatkan hanya peta yang dipesan (seperti yang Anda katakan, "ditentukan oleh urutan penyisipan").
K. Gol
1
jawaban ini dapat ditingkatkan dengan menunjukkan cara mengulangi keySet ()
4
Dari java 8 doc . LinkedHashMapyang urutan pengulangannya adalah urutan entri yang terakhir diakses
TRiNE
1
@TRiNE Saya tidak mengikuti komentar Anda, tetapi saya mungkin telah melewatkan beberapa konteks. Secara default LinkedHashMap, urutan iterasi adalah urutan penyisipan, tetapi Anda dapat menggunakan konstruktor yang berbeda untuk menentukan urutan akses sebagai gantinya. docs.oracle.com/javase/8/docs/api/java/util/…
rob
212

Apakah ada objek yang bertindak seperti Peta untuk menyimpan dan mengakses pasangan kunci / nilai, tetapi dapat mengembalikan daftar kunci yang dipesan dan daftar nilai yang diurutkan, sehingga daftar kunci dan nilai berada dalam urutan yang sama?

Anda sedang mencari java.util.LinkedHashMap . Anda akan mendapatkan daftar Peta. Masukkan pasangan <K, V> , yang selalu diulang dalam urutan yang sama. Urutan itu sama dengan urutan Anda memasukkan item. Atau, gunakan java.util.SortedMap , di mana kunci harus memiliki urutan alami atau memilikinya yang ditentukan oleh a Comparator.

John Feminella
sumber
14
Dan untuk hanya menyimpan pembaca mengecek ini, karena sulit untuk memverifikasi dengan pengujian, keySet()metode ini secara efektif mengembalikan LinkedHashSet yang mencerminkan urutan put()panggilan Anda . Perhatikan bahwa panggilan berulang put()untuk kunci yang sama tidak akan mengubah urutan kecuali Anda remove()kunci sebelumnya.
Glenn Lawrence
Dari java 8 doc . LinkedHashMapyang urutan pengulangannya adalah urutan entri yang terakhir diakses
TRiNE
24

LinkedHashMap mempertahankan urutan kunci.

java.util.LinkedHashMap tampaknya berfungsi sama seperti HashMap normal.

VoNWooDSoN
sumber
1
Ini tidak memberikan jawaban untuk pertanyaan itu. Untuk mengkritik atau meminta klarifikasi dari seorang penulis, tinggalkan komentar di bawah posting mereka - Anda selalu dapat mengomentari posting Anda sendiri, dan begitu Anda memiliki reputasi yang cukup, Anda akan dapat mengomentari setiap posting .
ianaya89
2
@ ianaya89 Saya pikir ini adalah jawaban yang nyata, tetapi sangat mirip dengan jawaban John Feminella !
T30
1
Jika Anda ingin mendapatkan peta yang dipesan, tempat entri disimpan dalam urutan itu saat Anda memasukkannya ke dalam peta, maka LinkedHashMap adalah jawaban yang tepat. Jika Anda ingin mengurutkan entri dalam peta Anda sendiri dari formulir yang Anda masukkan, daripada SortedMap adalah jawaban yang tepat.
Ralph
@TRiNE Java 8 doc yang Anda tautkan mengatakan ada dua mode pemesanan yang mungkin: insertion-order dan access-order. Anda berpikir tentang yang terakhir yang dipanggil oleh penggunaan publik khusus constructor LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder). Konstruktor default membuat instance LinkedHashMap yang dipesan dengan sisipan.
Artur Łysik
1
@ ArturŁysik ya itu. Itu adalah kesalahan yang saya lakukan beberapa hari yang lalu. Saya akan memperbaikinya. Saya menghapus komentar. karena saya tidak lagi dapat mengeditnya
TRINE
7

Saya pikir koleksi terdekat yang akan Anda dapatkan dari kerangka kerja adalah SortedMap

bruno conde
sumber
3
Saya akan memilih jawaban ini jika saya pikir itu layak kehilangan poin untuk itu. Seperti jawaban di atas tunjukkan, jawaban Anda tidak memiliki informasi yang tepat tentang LinkedHashMap, dan sedikit penjelasan tentang SortedMap juga akan menyenangkan.
CorayThan
@CorayThan, dalam hal ini Anda memilih jawaban terbaik, bukan mengungguli orang lain yang mungkin benar tetapi bukan yang terbaik ...
bruno conde
1
Itu yang saya lakukan. Hanya mengatakan saya bisa mengerti mengapa seseorang akan memilih itu.
CorayThan
5

Anda dapat memanfaatkan antarmuka NavigableMap yang dapat diakses dan dilalui dalam urutan kunci naik atau turun. Antarmuka ini dimaksudkan untuk menggantikan antarmuka SortedMap. Peta Navigable biasanya disortir berdasarkan urutan kuncinya, atau oleh Pembanding yang disediakan pada waktu pembuatan peta.

Ada tiga implementasi yang paling berguna: TreeMap , ImmutableSortedMap , dan ConcurrentSkipListMap .

Contoh TreeMap:

TreeMap<String, Integer> users = new TreeMap<String, Integer>();
users.put("Bob", 1);
users.put("Alice", 2);
users.put("John", 3);

for (String key: users.keySet()) {
  System.out.println(key + " (ID = "+ users.get(key) + ")");
}

Keluaran:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)
Vitalii Fedorenko
sumber
2

tl; dr

Untuk menjaga Map< Integer , String >agar urutan diurutkan berdasarkan kunci, gunakan salah satu dari dua kelas yang mengimplementasikan SortedMap/ NavigableMapinterface:

  • TreeMap
  • ConcurrentSkipListMap

Jika memanipulasi peta dalam utas tunggal, gunakan yang pertama TreeMap,. Jika memanipulasi seluruh utas, gunakan yang kedua ConcurrentSkipListMap,.

Untuk detailnya, lihat tabel di bawah dan diskusi berikut.

Detail

Berikut ini adalah tabel grafik yang saya buat menunjukkan fitur dari sepuluh Mapimplementasi yang dibundel dengan Java 11.

The NavigableMapantarmuka adalah apa yang SortedMapseharusnya di tempat pertama. The SortedMaplogis harus dihapus tetapi tidak bisa karena beberapa implementasi peta pihak ke-3 mungkin menggunakan antarmuka.

Seperti yang Anda lihat dalam tabel ini, hanya dua kelas yang mengimplementasikan SortedMap/ NavigableMapinterface:

Kedua kunci ini disimpan dalam urutan yang diurutkan, baik berdasarkan urutan aslinya (menggunakan compareTometode Comparable( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Comparable.html ) interface) atau dengan Comparatorimplementasi yang Anda lewati. Perbedaan antara dua kelas ini adalah bahwa yang kedua, ConcurrentSkipListMapadalah benang-aman , sangat bersamaan .

Lihat juga kolom Iteration order pada tabel di bawah ini.

  • The LinkedHashMapkelas mengembalikan entri yang oleh urutan di mana mereka awalnya dimasukkan .
  • EnumMapmengembalikan entri dalam urutan dimana kelas enum dari kunci didefinisikan . Misalnya, peta yang karyawannya mencakup hari mana dalam seminggu ( Map< DayOfWeek , Person >) menggunakan DayOfWeekkelas enum yang dibangun di Jawa. Enum itu didefinisikan dengan Senin pertama dan Minggu lalu. Jadi entri dalam iterator akan muncul dalam urutan itu.

Enam implementasi lainnya tidak membuat janji tentang urutan di mana mereka melaporkan entri mereka.

Tabel implementasi peta di Java 11, membandingkan fitur-fiturnya

Basil Bourque
sumber
0

Saya telah menggunakan peta Simple Hash, daftar tertaut, dan Koleksi untuk mengurutkan Peta berdasarkan nilai.

import java.util.*;
import java.util.Map.*;
public class Solution {

    public static void main(String[] args) {
        // create a simple hash map and insert some key-value pairs into it
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("Python", 3);
        map.put("C", 0);
        map.put("JavaScript", 4);
        map.put("C++", 1);
        map.put("Golang", 5);
        map.put("Java", 2);
        // Create a linked list from the above map entries
        List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
        // sort the linked list using Collections.sort()
        Collections.sort(list, new Comparator<Entry<String, Integer>>(){
        @Override
         public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
        return m1.getValue().compareTo(m2.getValue());
        }
      });
      for(Entry<String, Integer> value: list) {
         System.out.println(value);
     }
   }
}

Outputnya adalah:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Steffi Keran Rani J
sumber