Bản đồ đặt hàng Java


322

Trong Java, có một đối tượng hoạt động như một Bản đồ để lưu trữ và truy cập các cặp khóa / giá trị, nhưng có thể trả về một danh sách các khóa và một danh sách các giá trị theo thứ tự, sao cho các danh sách khóa và giá trị theo cùng một thứ tự?

Vì vậy, như lời giải thích theo mã, tôi đang tìm kiếm thứ gì đó hoạt động giống như OrderedMap hư cấu của tôi:

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);
}

4
Nếu tất cả những gì bạn muốn làm là lặp lại qua cả hai cùng một lúc, thì Map.entryset () sẽ cho phép bạn làm điều đó trên bất kỳ bản đồ nào. LinkedHashMap có một thứ tự được xác định rõ, nhưng đối với bất kỳ Bản đồ nào, bộ mục nhập phản ánh các cặp khóa / giá trị.
Pete Kirkham

5
Mã này không phải là một ví dụ hay vì bất kỳ triển khai Bản đồ nào cũng sẽ hoạt động như mã mẫu của bạn. Sắp xếp, đặt hàng hay không.
Peter Lawrey

2
Trong triển khai Sun JDK, các bộ được trả về bởi các bộ getKeys và getValues ​​() được hỗ trợ bởi entryset () trong bản đồ, do đó sẽ có cùng thứ tự lặp, đó là những gì mẫu thử nghiệm của bạn.
Pete Kirkham

4
Thật thú vị, tôi không bao giờ nhận thấy điều đó. Tuy nhiên, hãy gọi tôi là điên, nhưng tôi không muốn đưa ra các giả định về việc triển khai không được xác minh rõ ràng bởi giao diện. Tôi đã bị đốt cháy quá nhiều lần trong quá khứ.
Whats

2
Điều này nên được đặt tên là Bản đồ được sắp xếp Java, vì Bản đồ được sắp xếp là một cái gì đó khác biệt - xem LinkedHashMap.
Ondra Žižka

Câu trả lời:


397

Các SortedMap giao diện (với việc thực hiện TreeMap ) nên bạn bè của bạn.

Giao diện có các phương thức:

  • keySet() trong đó trả về một tập hợp các khóa theo thứ tự tăng dần
  • values() trong đó trả về một tập hợp tất cả các giá trị theo thứ tự tăng dần của các khóa tương ứng

Vì vậy, giao diện này đáp ứng chính xác yêu cầu của bạn. Tuy nhiên, các phím phải có một thứ tự có ý nghĩa. Mặt khác, bạn có thể sử dụng LinkedHashMap trong đó thứ tự được xác định bởi thứ tự chèn.


2
ví dụ: Sắp xếp bản đồ <Chuỗi, Đối tượng> map = new TreeMap <> ();
Ben

7
Để sử dụng TreeMap, lớp yêu cầu phải thực hiện giao diện so sánh. Nếu không, một số loại RuntimeException sẽ bị ném. TreeMap cũng đã sắp xếp bản đồ, nhưng tôi nghĩ tác giả muốn sử dụng bản đồ chỉ được sắp xếp (không được sắp xếp). LinkedHashMap là lựa chọn tốt để chỉ nhận bản đồ được đặt hàng (như bạn đã nói, "được xác định bằng thứ tự chèn").
K. Gol

1
câu trả lời này có thể được cải thiện bằng cách hiển thị cách lặp lại trên

4
Từ tài liệu java 8 . LinkedHashMapcó thứ tự lặp là thứ tự các mục nhập của nó được truy cập lần cuối
TRiNE

1
@TRiNE Tôi không theo dõi bình luận của bạn, nhưng tôi có thể đã bỏ lỡ một số bối cảnh. Theo mặc định LinkedHashMap, thứ tự lặp là thứ tự chèn, nhưng bạn có thể sử dụng một hàm tạo khác để chỉ định thứ tự truy cập thay thế. docs.oracle.com/javase/8/docs/api/java/util/ Kẻ
cướp

212

Có một đối tượng hoạt động như một Bản đồ để lưu trữ và truy cập các cặp khóa / giá trị, nhưng có thể trả về một danh sách các khóa được sắp xếp và một danh sách các giá trị được sắp xếp, sao cho các danh sách khóa và giá trị theo cùng một thứ tự không?

Bạn đang tìm kiếm java.util.LinkedHashMap . Bạn sẽ nhận được một danh sách các cặp Map.Entry <K, V> , luôn được lặp theo cùng một thứ tự. Thứ tự đó giống như thứ tự mà bạn đặt các mục vào. Ngoài ra, hãy sử dụng java.util.SortMap , trong đó các khóa phải có thứ tự tự nhiên hoặc được chỉ định bởi a Comparator.


14
Và để chỉ giúp người đọc kiểm tra kỹ điều này, bởi vì thật khó để xác minh bằng cách kiểm tra, keySet()phương thức này trả về hiệu quả một LinkedHashset phản ánh thứ tự các put()cuộc gọi của bạn . Lưu ý rằng các cuộc gọi lặp lại put()cho cùng một khóa sẽ không thay đổi thứ tự trừ khi bạn remove()bấm phím trước.
Glenn Lawrence

Từ tài liệu java 8 . LinkedHashMapcó thứ tự lặp là thứ tự mà các mục của nó được truy cập lần cuối
TRiNE

24

LinkedHashMap duy trì thứ tự của các khóa.

java.util.LinkedHashMap dường như hoạt động giống như một HashMap bình thường.


1
Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào .
ianaya89

2
@ ianaya89 Tôi nghĩ rằng đây là một câu trả lời thực sự, nhưng nó rất giống với câu trả lời của John Women'sella !
T30

1
Nếu bạn muốn có được một bản đồ được đặt hàng, trong đó các mục được lưu trữ theo thứ tự đó khi bạn đặt chúng vào bản đồ, hơn LinkedHashMap là câu trả lời đúng. Nếu bạn muốn sắp xếp các mục trong biểu mẫu độc lập trên bản đồ của mình theo thứ tự bạn đặt chúng, thì Sắp xếp Bản đồ là câu trả lời đúng.
Ralph

@TRiNE Tài liệu java 8 mà bạn liên kết cho biết có hai chế độ đặt hàng có thể có: thứ tự chèn và thứ tự truy cập. Bạn nghĩ về cái sau được gọi bằng cách sử dụng một hàm tạo đặc biệt công khai LinkedHashMap (int initCapacity, float loadFactor, boolean accessOrder). Hàm tạo mặc định tạo một cá thể LinkedHashMap theo thứ tự chèn.
Artur Łysik

1
@ ArturŁysik đúng vậy. Đó là một sai lầm được thực hiện bởi tôi ngày trước. Tôi sẽ sửa nó. Tôi đang xóa bình luận. vì tôi không còn có thể chỉnh sửa nó
TRiNE

7

Tôi nghĩ rằng bộ sưu tập gần nhất bạn sẽ nhận được từ khung là Sắp xếp Bản đồ


3
Tôi sẽ bỏ phiếu cho câu trả lời này nếu tôi nghĩ rằng nó đáng để mất điểm cho nó. Như câu trả lời ở trên chỉ ra, câu trả lời của bạn thiếu thông tin thích hợp về LinkedHashMap và một lời giải thích nhỏ về SortedMap cũng sẽ rất hay.
CorayThan

@CorayThan, trong trường hợp đó, bạn nêu lên những câu trả lời hay nhất, không đánh giá thấp những người khác có thể đúng nhưng không phải là tốt nhất ...
bruno conde

1
Đó là những gì tôi đã làm. Chỉ cần nói rằng tôi có thể hiểu tại sao ai đó sẽ bỏ phiếu.
CorayThan

5

Bạn có thể tận dụng giao diện NavigableMap có thể được truy cập và duyệt qua theo thứ tự khóa tăng dần hoặc giảm dần. Giao diện này nhằm thay thế giao diện SortedMap. Bản đồ có thể điều hướng thường được sắp xếp theo thứ tự tự nhiên của các khóa hoặc theo Bộ so sánh được cung cấp tại thời điểm tạo bản đồ.

Có ba cách triển khai hữu ích nhất của nó: TreeMap , ImmutableSorticMapConcảnSkipListMap .

Ví dụ về 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) + ")");
}

Đầu ra:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)



2

tl; dr

Để theo Map< Integer , String >thứ tự được sắp xếp theo khóa, hãy sử dụng một trong hai lớp thực hiện SortedMap/ NavigableMapgiao diện:

  • TreeMap
  • ConcurrentSkipListMap

Nếu thao tác trên bản đồ trong một luồng, sử dụng đầu tiên , TreeMap. Nếu thao tác trên các chủ đề, sử dụng thứ hai , ConcurrentSkipListMap.

Để biết chi tiết, xem bảng dưới đây và các cuộc thảo luận sau đây.

Chi tiết

Đây là một bảng đồ họa tôi đã thực hiện cho thấy các tính năng của mười Maptriển khai được gói cùng với Java 11.

Các NavigableMapgiao diện là những gì SortedMapcần phải có được ở nơi đầu tiên. CácSortedMap logic cần được loại bỏ nhưng không thể như một số triển khai bản đồ của bên thứ 3 có thể được sử dụng giao diện.

Như bạn có thể thấy trong bảng này, chỉ có hai lớp thực hiện SortedMap/ NavigableMapgiao diện:

Cả hai đều giữ các khóa theo thứ tự được sắp xếp, theo thứ tự tự nhiên của chúng (sử dụng compareTophương thức của Comparable( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Giao diện so sánh.html ) hoặc bằng cách Comparatortriển khai bạn vượt qua. Sự khác biệt giữa hai loại cổ phiếu này là một trong những thứ hai, ConcurrentSkipListMapthread-safe , cao đồng thời .

Xem thêm cột thứ tự lặp trong bảng dưới đây.

  • Các LinkedHashMaplớp trả về mục của nó bởi thứ tự mà họ đã đưa ban đầu .
  • EnumMaptrả về các mục theo thứ tự mà lớp enum của khóa được xác định . Ví dụ, bản đồ mà nhân viên đang trình bày vào ngày nào trong tuần ( Map< DayOfWeek , Person >) sử dụng DayOfWeeklớp enum được tích hợp trong Java. Enum đó được xác định với thứ Hai đầu tiên và Chủ nhật cuối cùng. Vì vậy, các mục trong một iterator sẽ xuất hiện theo thứ tự đó.

Sáu triển khai khác không hứa hẹn về thứ tự mà họ báo cáo các mục nhập của họ.

Bảng triển khai bản đồ trong Java 11, so sánh các tính năng của chúng


0

Tôi đã sử dụng bản đồ Hash đơn giản, danh sách được liên kết và Bộ sưu tập để sắp xếp Bản đồ theo các giá trị.

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);
     }
   }
}

Đầu ra là:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.