Saya relatif baru ke Jawa, dan sering menemukan bahwa saya perlu mengurutkan Map<Key, Value>
nilai-nilai.
Karena nilainya tidak unik, saya menemukan diri saya mengubah keySet
menjadi array
, dan mengurutkan array melalui sortir dengan komparator kustom yang mengurutkan pada nilai yang terkait dengan kunci.
Apakah ada cara yang lebih mudah?
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
dan sepertiCollections.sort ....
itu.Jawaban:
Ini versi ramah-generik:
sumber
forEachOrdered
sebagai gantiforEach
, karena dokumenforEach
negara menyatakan: "Perilaku operasi ini secara eksplisit tidak deterministik."?Catatan penting:
Kode ini dapat pecah dalam berbagai cara. Jika Anda bermaksud menggunakan kode yang disediakan, pastikan untuk membaca komentar dan juga untuk mengetahui implikasinya. Misalnya, nilai tidak lagi dapat diambil dengan kunci mereka. (
get
selalu kembalinull
.)Tampaknya jauh lebih mudah daripada semua hal di atas. Gunakan TreeMap sebagai berikut:
Keluaran:
sumber
return ((Comparable)base.get(a).compareTo(((Comparable)base.get(b)))
?map.put("A","1d");map.put("B","1d");map.put("C",67d);map.put("D",99.5d);
Java 8 menawarkan jawaban baru: ubah entri menjadi arus, dan gunakan kombinator pembanding dari Map.Entry:
Ini akan memungkinkan Anda mengonsumsi entri yang diurutkan dalam urutan nilai naik. Jika Anda ingin nilai menurun, cukup membalikkan komparator:
Jika nilainya tidak sebanding, Anda dapat melewati komparator eksplisit:
Anda kemudian dapat melanjutkan untuk menggunakan operasi aliran lain untuk mengkonsumsi data. Misalnya, jika Anda ingin top 10 di peta baru:
Atau cetak ke
System.out
:sumber
parallelStream()
dalam kasus ini?Tiga jawaban 1 baris ...
Saya akan menggunakan
Google CollectionsGuava untuk melakukan ini - jika nilaiComparable
Anda maka Anda dapat menggunakannyaYang akan membuat fungsi (objek) untuk peta [yang mengambil salah satu kunci sebagai input, mengembalikan nilai masing-masing], dan kemudian menerapkan urutan alami (sebanding) dengan mereka [nilai-nilai].
Jika mereka tidak sebanding, maka Anda harus melakukan sesuatu di sepanjang garis
Ini dapat diterapkan ke TreeMap (sebagai
Ordering
ekstensiComparator
), atau LinkedHashMap setelah pengurutanNB : Jika Anda akan menggunakan TreeMap, ingatlah bahwa jika perbandingan == 0, maka item tersebut sudah ada dalam daftar (yang akan terjadi jika Anda memiliki beberapa nilai yang membandingkan yang sama). Untuk meringankan ini, Anda dapat menambahkan kunci Anda ke komparator seperti itu (dengan anggapan bahwa kunci dan nilai Anda
Comparable
):= Terapkan pemesanan alami untuk nilai yang dipetakan oleh kunci, dan gabungkan bahwa dengan pemesanan alami kunci
Perhatikan bahwa ini masih tidak berfungsi jika kunci Anda dibandingkan dengan 0, tetapi ini harus cukup untuk sebagian besar
comparable
item (sepertihashCode
,equals
dancompareTo
sering disinkronkan ...)Lihat Memesan.onResultOf () dan Functions.forMap () .
Penerapan
Jadi sekarang kita memiliki pembanding yang melakukan apa yang kita inginkan, kita perlu mendapatkan hasil darinya.
Sekarang ini kemungkinan besar akan berhasil, tetapi:
TreeMap
; tidak ada gunanya mencoba membandingkan kunci yang dimasukkan ketika tidak memiliki nilai sampai setelah put, yaitu, itu akan pecah sangat cepatPoin 1 adalah sedikit pemecah kesepakatan bagi saya; koleksi google sangat malas (yang bagus: Anda dapat melakukan hampir semua operasi dalam sekejap; pekerjaan nyata dilakukan ketika Anda mulai menggunakan hasilnya), dan ini membutuhkan penyalinan secara keseluruhan peta!
Jawaban "Lengkap" / Peta yang disortir langsung berdasarkan nilai
Jangan khawatir; jika Anda cukup terobsesi untuk memiliki peta "langsung" yang diurutkan dengan cara ini, Anda tidak dapat menyelesaikan tidak satu tetapi keduanya (!) dari masalah di atas dengan sesuatu yang gila seperti berikut:
Catatan: Ini telah berubah secara signifikan pada Juni 2012 - kode sebelumnya tidak pernah bisa berfungsi: HashMap internal diperlukan untuk mencari nilai-nilai tanpa membuat loop tak terbatas antara
TreeMap.get()
->compare()
dancompare()
->get()
Ketika kami meletakkan, kami memastikan bahwa peta hash memiliki nilai untuk komparator, dan kemudian dimasukkan ke TreeSet untuk disortir. Tapi sebelum itu kita periksa peta hash untuk melihat bahwa kuncinya sebenarnya bukan duplikat. Selain itu, pembanding yang kami buat juga akan menyertakan kunci sehingga nilai duplikat tidak menghapus kunci non-duplikat (karena perbandingan ==). 2 item ini sangat penting untuk memastikan kontrak peta disimpan; jika Anda pikir Anda tidak menginginkan itu, maka Anda hampir pada titik membalikkan peta sepenuhnya (ke
Map<V,K>
).Konstruktor perlu disebut sebagai
sumber
Ordering
hanya kayaComparator
. Saya sudah mencoba mengomentari setiap contoh (huruf miring di bawah masing-masing). "alami" menunjukkan bahwa objeknya adalahComparable
; itu seperti ComparableComparator dari apache common.onResultOf
berlaku fungsi untuk item yang dibandingkan. Jadi jika Anda memiliki fungsi yang menambahkan 1 ke integer, makanatural().onResultOf(add1Function).compare(1,2)
akhirnya akan melakukan2.compareTo(3)
ImmutableSetMultiMap
atauImmutableListMultiMap
mengandung koleksi variabel duplikat.Dari http://www.programmersheaven.com/download/49349/download.aspx
sumber
Dengan Java 8, Anda dapat menggunakan api stream untuk melakukannya dengan cara yang jauh lebih sedikit:
sumber
Collections.reverseOrder(comparing(Entry::getValue))
Entry.comparingByValue(Comparator.reverseOrder())
Mengurutkan kunci membutuhkan Pembanding untuk mencari setiap nilai untuk setiap perbandingan. Solusi yang lebih scalable akan menggunakan entriSet secara langsung, sejak saat itu nilai akan segera tersedia untuk setiap perbandingan (walaupun saya belum mendukung ini dengan angka).
Inilah versi generik dari hal semacam itu:
Ada beberapa cara untuk mengurangi rotasi memori untuk solusi di atas. ArrayList pertama yang dibuat misalnya dapat digunakan kembali sebagai nilai kembali; ini membutuhkan penindasan terhadap beberapa peringatan umum, tetapi mungkin layak untuk kode pustaka yang dapat digunakan kembali. Juga, Pembanding tidak harus dialokasikan kembali pada setiap doa.
Berikut adalah versi yang lebih efisien meskipun kurang menarik:
Terakhir, jika Anda perlu mengakses informasi yang disortir secara terus-menerus (bukan hanya menyortir sesekali), Anda dapat menggunakan multi-peta tambahan. Beri tahu saya jika Anda membutuhkan detail lebih lanjut ...
sumber
Perpustakaan commons-collections berisi solusi yang disebut TreeBidiMap . Atau, Anda bisa melihat di Google Collections API. Ini memiliki TreeMultimap yang dapat Anda gunakan.
Dan jika Anda tidak ingin menggunakan kerangka kerja ini ... mereka datang dengan kode sumber.
sumber
Saya telah melihat jawaban yang diberikan, tetapi banyak dari mereka lebih rumit daripada yang dibutuhkan atau menghapus elemen peta ketika beberapa kunci memiliki nilai yang sama.
Berikut adalah solusi yang menurut saya lebih baik:
Perhatikan bahwa peta diurutkan dari nilai tertinggi ke terendah.
sumber
Untuk mencapai ini dengan fitur-fitur baru di Java 8:
Entri diurutkan berdasarkan nilainya menggunakan pembanding yang diberikan. Atau, jika nilai Anda setara satu sama lain, tidak diperlukan pembanding eksplisit:
Daftar yang dikembalikan adalah snapshot dari peta yang diberikan pada saat metode ini dipanggil, sehingga tidak akan mencerminkan perubahan berikutnya ke yang lain. Untuk tampilan peta yang dapat diputar langsung:
Iterable yang dikembalikan menciptakan snapshot segar dari peta yang diberikan setiap kali iterated, jadi kecuali modifikasi bersamaan, itu akan selalu mencerminkan keadaan peta saat ini.
sumber
Buat komparator khusus dan gunakan sambil membuat objek TreeMap baru.
Gunakan kode di bawah ini di fungsi utama Anda
Keluaran:
sumber
Sementara saya setuju bahwa kebutuhan konstan untuk mengurutkan peta mungkin adalah bau, saya pikir kode berikut adalah cara termudah untuk melakukannya tanpa menggunakan struktur data yang berbeda.
}
Dan berikut ini adalah unit test yang memalukan:
}
Hasilnya adalah daftar Map.Entry objek yang diurutkan, dari mana Anda bisa mendapatkan kunci dan nilai.
sumber
Gunakan pembanding generik seperti:
sumber
Jawaban yang paling banyak dipilih tidak berfungsi ketika Anda memiliki 2 item yang setara. TreeMap meninggalkan nilai yang sama.
exmaple: map yang tidak disortir
hasil
Jadi tinggalkan E !!
Bagi saya itu berfungsi dengan baik untuk menyesuaikan pembanding, jika sama dengan tidak mengembalikan 0 tetapi -1.
dalam contoh:
sekarang kembali:
peta yang tidak disortir:
hasil:
sebagai tanggapan terhadap Aliens (2011 nov. 22): Saya menggunakan solusi ini untuk peta Integer Id dan nama, tetapi idenya sama, jadi mungkin kode di atas tidak benar (saya akan menulisnya dalam ujian dan memberi Anda kode yang benar), ini adalah kode untuk pengurutan Peta, berdasarkan solusi di atas:
dan ini adalah kelas tes (saya baru saja mengujinya, dan ini berfungsi untuk Integer, String Map:
di sini adalah kode untuk Pembanding Peta:
dan ini adalah testcase untuk ini:
keberanian Anda dapat membuat ini jauh lebih umum, tetapi saya hanya membutuhkannya untuk 1 case (Peta)
sumber
Alih-alih menggunakan
Collections.sort
karena beberapa saya sarankan menggunakanArrays.sort
. Sebenarnya yangCollections.sort
dilakukan adalah sesuatu seperti ini:Itu hanya memanggil
toArray
daftar dan kemudian menggunakanArrays.sort
. Dengan cara ini semua entri peta akan disalin tiga kali: sekali dari peta ke daftar sementara (baik itu LinkedList atau ArrayList), kemudian ke array sementara dan akhirnya ke peta baru.Solusi saya membatalkan langkah ini karena tidak membuat LinkedList yang tidak perlu. Ini kodenya, ramah-generik dan kinerja-optimal:
sumber
Ini adalah variasi dari jawaban Anthony, yang tidak berfungsi jika ada nilai duplikat:
Perhatikan bahwa itu agak di udara bagaimana menangani null.
Satu keuntungan penting dari pendekatan ini adalah ia benar-benar mengembalikan Peta, tidak seperti beberapa solusi lain yang ditawarkan di sini.
sumber
Pendekatan Terbaik
Keluaran
sumber
Masalah besar. Jika Anda menggunakan jawaban pertama (Google membawa Anda ke sini), ubah komparator untuk menambahkan klausa yang sama, jika tidak, Anda tidak bisa mendapatkan nilai dari sort_map dengan kunci:
sumber
Sudah ada banyak jawaban untuk pertanyaan ini, tetapi tidak ada yang memberi saya apa yang saya cari, implementasi peta yang mengembalikan kunci dan entri yang diurutkan berdasarkan nilai yang terkait, dan mempertahankan properti ini karena kunci dan nilai dimodifikasi di peta. Dua pertanyaan lain menanyakan hal ini secara khusus.
Saya membuat contoh ramah umum yang memecahkan kasus penggunaan ini. Implementasi ini tidak menghormati semua kontrak antarmuka Peta, seperti mencerminkan perubahan nilai dan penghapusan dalam set yang kembali dari keySet () dan entrySet () di objek asli. Saya merasa solusi seperti itu akan terlalu besar untuk dimasukkan dalam jawaban Stack Overflow. Jika saya berhasil membuat implementasi yang lebih lengkap, mungkin saya akan mempostingnya ke Github dan kemudian menghubungkannya dalam versi terbaru dari jawaban ini.
sumber
Entri Terlambat.
Dengan munculnya Java-8, kita dapat menggunakan stream untuk manipulasi data dengan cara yang sangat mudah / ringkas. Anda dapat menggunakan stream untuk mengurutkan entri peta berdasarkan nilai dan membuat LinkedHashMap yang mempertahankan iterasi urutan penyisipan .
Misalnya:
Untuk pemesanan terbalik, ganti:
dengan
sumber
Entry.comparingByValue()
(seperti jawaban assylias di atas stackoverflow.com/a/22132422/1480587 ) ataucomparing(Entry<Key,Value>::getValue).thenComparing(Entry::getKey)
yang Anda gunakan? Saya mengerti Anda juga membandingkan kunci jika nilainya identik, bukan? Saya perhatikan bahwa pengurutan menjaga urutan elemen dengan nilai yang sama - jadi apakah pengurutan menurut kunci diperlukan jika kunci sudah diurutkan sebelumnya?Peta yang Diberikan
Urutkan peta berdasarkan nilai dalam urutan menaik
Urutkan peta berdasarkan nilai dalam urutan menurun
Keluaran:
{perangkat lunak = 50, teknologi = 70, USA = 100, pekerjaan = 200, peluang = 200}
{jobs = 200, peluang = 200, USA = 100, teknologi = 70, perangkat lunak = 50}
sumber
Bergantung pada konteksnya, menggunakan
java.util.LinkedHashMap<T>
yang mengingat urutan item ditempatkan ke dalam peta. Kalau tidak, jika Anda perlu mengurutkan nilai berdasarkan pemesanan alami mereka, saya akan merekomendasikan mempertahankan Daftar terpisah yang dapat diurutkan melaluiCollections.sort()
.sumber
Sejak TreeMap <> tidak berfungsi untuk nilai yang bisa sama, saya menggunakan ini:
Anda mungkin ingin meletakkan daftar di LinkedHashMap , tetapi jika Anda hanya akan mengulanginya segera, itu berlebihan ...
sumber
Ini terlalu rumit. Peta tidak seharusnya melakukan pekerjaan seperti menyortir berdasarkan Nilai. Cara termudah adalah membuat Kelas Anda sendiri sehingga sesuai dengan kebutuhan Anda.
Dalam contoh yang lebih rendah, Anda seharusnya menambahkan TreeMap sebagai pembanding di tempat *. Tetapi dengan java API hanya memberikan kunci pembanding, bukan nilai. Semua contoh yang dinyatakan di sini didasarkan pada 2 Peta. Satu hash dan satu Tree baru. Aneh sekali.
Contoh:
Jadi ubah peta menjadi seperangkat dengan cara ini:
Anda akan membuat kelas
Results
,dan kelas pembanding:
Dengan cara ini Anda dapat dengan mudah menambahkan lebih banyak dependensi.
Dan sebagai poin terakhir saya akan menambahkan iterator sederhana:
sumber
Berdasarkan kode @devinmoore, metode penyortiran peta menggunakan obat generik dan mendukung pemesanan naik dan turun.
sumber
Berikut ini adalah solusi OO (yaitu, tidak menggunakan
static
metode):Dengan ini disumbangkan ke domain publik.
sumber
Afaik cara yang paling bersih adalah menggunakan koleksi untuk mengurutkan peta berdasarkan nilai:
sumber
Beberapa perubahan sederhana untuk memiliki peta yang diurutkan dengan pasangan yang memiliki nilai duplikat. Dalam metode bandingkan (kelas ValueComparator) ketika nilainya sama, jangan mengembalikan 0 tetapi mengembalikan hasil membandingkan 2 kunci. Kunci berbeda di peta sehingga Anda berhasil menjaga nilai duplikat (yang diurutkan berdasarkan kunci dengan cara). Jadi contoh di atas dapat dimodifikasi seperti ini:
sumber
Tentu solusi Stephen benar-benar hebat, tetapi bagi mereka yang tidak bisa menggunakan Jambu:
Inilah solusi saya untuk mengurutkan berdasarkan nilai peta. Solusi ini menangani kasus di mana ada dua kali nilai yang sama dll ...
Eksekutif: http://www.ideone.com/dq3Lu
Hasil:
Semoga ini bisa membantu beberapa orang
sumber
Jika Anda memiliki kunci duplikat dan hanya kumpulan data kecil (<1000) dan kode Anda tidak kritis kinerja, Anda bisa melakukan hal berikut:
inputUnsortedMap adalah input ke kode.
Variabel diurutkanOutputMap akan berisi data dalam urutan menurun ketika diulangi. Untuk mengubah urutan, ubah saja> ke <dalam pernyataan if.
Bukan jenis tercepat tetapi melakukan pekerjaan tanpa ketergantungan tambahan.
sumber