HashMap với nhiều giá trị dưới cùng một khóa


199

Chúng tôi có thể triển khai HashMap với một khóa và hai giá trị không. Cũng như HashMap?

Xin hãy giúp tôi, bằng cách nói (nếu không có cách nào) để thực hiện việc lưu trữ ba giá trị với một làm khóa?



Cảm ơn bạn bè ... nhưng tôi có một số hạn chế khi sử dụng MultiHashMap
vidhya

Câu trả lời:


266

Bạn có thể:

  1. Sử dụng bản đồ có một danh sách làm giá trị. Map<KeyType, List<ValueType>>.
  2. Tạo một lớp bao bọc mới và đặt các thể hiện của trình bao bọc này trong bản đồ. Map<KeyType, WrapperType>.
  3. Sử dụng một tuple like class (tiết kiệm tạo ra nhiều hàm bao). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Sử dụng bản đồ mulitple cạnh nhau.

Ví dụ

1. Bản đồ với danh sách là giá trị

// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();    

// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);

// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];

Nhược điểm với phương pháp này là danh sách không bị ràng buộc với chính xác hai giá trị.

2. Sử dụng lớp bao bọc

// define our wrapper
class Wrapper {
    public Wrapper(Person person1, Person person2) {
       this.person1 = person1;
       this.person2 = person2;
    }

    public Person getPerson1 { return this.person1; }
    public Person getPerson2 { return this.person2; }

    private Person person1;
    private Person person2;
}

// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();

// populate it
Wrapper people = new Wrapper();
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
                                        new Person("Bob Jones"));

// read from it
Wrapper bobs = peopleByForename.get("Bob");
Person bob1 = bobs.getPerson1;
Person bob2 = bobs.getPerson2;

Nhược điểm của phương pháp này là bạn phải viết rất nhiều mã nồi hơi cho tất cả các lớp container rất đơn giản này.

3. Sử dụng bộ dữ liệu

// you'll have to write or download a Tuple class in Java, (.NET ships with one)

// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();

// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
                                       new Person("Bob Jones"));

// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;

Đây là giải pháp tốt nhất theo ý kiến ​​của tôi.

4. Nhiều bản đồ

// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();

// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));

// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];

Nhược điểm của giải pháp này là không rõ ràng rằng hai bản đồ có liên quan với nhau, một lỗi lập trình có thể thấy hai bản đồ không đồng bộ.


Xin chào Paul ... bạn có thể nói rõ hơn một chút không ...? Bằng một ví dụ ...?
vidhya

@vidhya: đặc biệt phù hợp với vấn đề của bạn? Là đối tượng mulitple của bạn cùng loại hoặc khác nhau?
Paul Ruane

Ví dụ sẽ là thực sự tuyệt vời.
Xonatron

@Paul, bất kỳ mã ví dụ đơn giản nào cho # 3 Map<KeyType, Tuple<Value1Type, Value2Type>>
Joarder Kamal

@CoolMind Tôi chắc chắn mọi người có thể khắc phục những lỗi sai: hoặc bạn có thể sửa chúng?
Paul Ruane

61

Không, không chỉ là a HashMap. Về cơ bản, bạn cần HashMapmột khóa từ một khóa đến một tập hợp các giá trị.

Nếu bạn hài lòng khi sử dụng các thư viện bên ngoài, Guava có chính xác khái niệm này Multimapvới các triển khai như ArrayListMultimapHashMultimap.


@ Jon, bạn có thể cung cấp một ví dụ hoạt động trong Java cho câu hỏi trên được hỏi bởi OP. Rất đánh giá cao nếu bạn có thể đăng nó
Deepak

2
@Deepak: Tìm kiếm ví dụ multimap ổi và bạn sẽ tìm thấy mã mẫu.
Jon Skeet

1
@Deepak: Về cơ bản, bạn sẽ xây dựng một cái gì đó giống như ArrayListMultimapmình ... hoặc chỉ sử dụng một HashMap<String, List<Integer>>hoặc bất cứ điều gì. Về cơ bản, bạn cần tạo một danh sách trống bất cứ khi nào một giá trị được thêm vào.
Jon Skeet

1
bạn có một ví dụ làm việc choHashMap<String, List<Integer>>
Deepak

9
@Deepak: Tôi khuyên bạn nên thử tự tạo một ví dụ và nếu bạn gặp khó khăn, hãy đặt câu hỏi bao gồm mã theo như bạn đã nhận được. Bạn sẽ học được nhiều hơn theo cách đó.
Jon Skeet

23

Một lựa chọn thú vị khác là sử dụng MultiValuedMap từ Apache Commons. Hãy xem tất cả các lớp triển khai đã biết ở đầu trang để triển khai chuyên ngành.

Thí dụ:

HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()

có thể được thay thế bằng

MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();

Vì thế,

map.put(key, "A");
map.put(key, "B");
map.put(key, "C");

Collection<String> coll = map.get(key);

sẽ dẫn đến bộ sưu tập collchứa "A", "B" và "C".


13

Hãy xem Multimaptừ các thư viện ổi và việc thực hiện nó -HashMultimap

Một bộ sưu tập tương tự như Bản đồ, nhưng có thể liên kết nhiều giá trị với một khóa duy nhất. Nếu bạn gọi put (K, V) hai lần, với cùng một khóa nhưng các giá trị khác nhau, multimap chứa ánh xạ từ khóa tới cả hai giá trị.


7

Tôi sử dụng Map<KeyType, Object[]>để liên kết nhiều giá trị với một khóa trong Bản đồ. Bằng cách này, tôi có thể lưu trữ nhiều giá trị thuộc các loại khác nhau được liên kết với một khóa. Bạn phải cẩn thận bằng cách duy trì thứ tự chèn và truy xuất thích hợp từ Object [].

Ví dụ: Xem xét, chúng tôi muốn lưu trữ thông tin sinh viên. Key là id, trong khi chúng tôi muốn lưu trữ tên, địa chỉ và email liên quan đến sinh viên.

       //To make entry into Map
        Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
        String[] studentInformationArray = new String[]{"name", "address", "email"};
        int studenId = 1;
        studenMap.put(studenId, studentInformationArray);

        //To retrieve values from Map
        String name = studenMap.get(studenId)[1];
        String address = studenMap.get(studenId)[2];
        String email = studenMap.get(studenId)[3];

1
Đối với tôi đây là câu trả lời tốt nhất. Nó đơn giản hơn, súc tích hơn và ít trừu tượng hơn.
Morey

6
HashMap<Integer,ArrayList<String>> map = new    HashMap<Integer,ArrayList<String>>();

ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);

4

Chỉ cần cho bản ghi, giải pháp JDK8 thuần túy sẽ sử dụng Map::computephương thức:

map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);

Nhu la

public static void main(String[] args) {
    Map<String, List<String>> map = new HashMap<>();

    put(map, "first", "hello");
    put(map, "first", "foo");
    put(map, "bar", "foo");
    put(map, "first", "hello");

    map.forEach((s, strings) -> {
        System.out.print(s + ": ");
        System.out.println(strings.stream().collect(Collectors.joining(", ")));
    });
}

private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
    map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}

với đầu ra:

bar: foo
first: hello, foo, hello

Lưu ý rằng để đảm bảo tính nhất quán trong trường hợp nhiều luồng truy cập cấu trúc dữ liệu này ConcurrentHashMapCopyOnWriteArrayListví dụ cần phải được sử dụng.


Nó là tốt hơn để sử dụng computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
saka1029

3

Nếu bạn sử dụng Spring Framework . Có : org.springframework.util.MultiValueMap.

Để tạo bản đồ đa giá trị không thể thay đổi:

Map<String,List<String>> map = ...
MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);

Hoặc dùng org.springframework.util.LinkedMultiValueMap


2

Có và không. Giải pháp là xây dựng một Wrapper clas cho các giá trị của bạn có chứa 2 (3 hoặc nhiều hơn) các giá trị tương ứng với khóa của bạn.



2

Cách dễ nhất là sử dụng thư viện bộ sưu tập google:

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

public class Test {

    public static void main(final String[] args) {

        // multimap can handle one key with a list of values
        final Multimap<String, String> cars = ArrayListMultimap.create();
        cars.put("Nissan", "Qashqai");
        cars.put("Nissan", "Juke");
        cars.put("Bmw", "M3");
        cars.put("Bmw", "330E");
        cars.put("Bmw", "X6");
        cars.put("Bmw", "X5");

        cars.get("Bmw").forEach(System.out::println);

        // It will print the:
        // M3
        // 330E
        // X6
        // X5
    }

}

liên kết maven: https://mvnreposective.com/artifact/com.google.collections/google-collections/1.0-rc2

thêm về điều này: http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html


1
String key= "services_servicename"

ArrayList<String> data;

for(int i = 0; i lessthen data.size(); i++) {
    HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
    servicesNameHashmap.put(key,data.get(i).getServiceName());
    mServiceNameArray.add(i,servicesNameHashmap);
}

Tôi đã có kết quả tốt nhất.

Bạn chỉ cần tạo HashMaplike mới

HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();

trong forvòng lặp của bạn . Nó sẽ có cùng hiệu ứng như cùng khóa và nhiều giá trị.


1
 import java.io.*;
 import java.util.*;

 import com.google.common.collect.*;

 class finTech{
public static void main(String args[]){
       Multimap<String, String> multimap = ArrayListMultimap.create();
       multimap.put("1","11");
       multimap.put("1","14");
       multimap.put("1","12");
       multimap.put("1","13");
       multimap.put("11","111");
       multimap.put("12","121");
        System.out.println(multimap);
        System.out.println(multimap.get("11"));
   }                                                                                            
 }                                                                    

Đầu ra:

     {"1"=["11","12","13","14"],"11"=["111"],"12"=["121"]}

      ["111"]

Đây là thư viện Google-Guava cho các chức năng tiện ích. Đây là giải pháp cần thiết.


Đó là một giải pháp hợp lệ và tôi đã sử dụng phương pháp này trong nhiều lần.
letowianka

vâng nó hoạt động nhưng nó đang hiển thị dữ liệu trong [] formate tôi muốn các mục đó lần lượt làm thế nào để có được điều đó. Tôi bị mắc kẹt ở đây
Sunil Chaudhary

0

Tôi không thể đăng bài trả lời về bình luận của Paul vì vậy tôi đang tạo bình luận mới cho Vidhya tại đây:

Wrapper sẽ là một giá SuperClasstrị cho hai lớp mà chúng ta muốn lưu trữ dưới dạng giá trị.

và bên trong lớp trình bao bọc, chúng ta có thể đặt các liên kết làm đối tượng biến đối tượng cho hai đối tượng lớp.

ví dụ

class MyWrapper {

 Class1 class1obj = new Class1();
 Class2 class2obj = new Class2();
...
}

và trong HashMap, chúng ta có thể đặt theo cách này,

Map<KeyObject, WrapperObject> 

WrapperObj sẽ có các biến lớp:class1Obj, class2Obj


0

Bạn có thể làm điều đó ngầm.

// Create the map. There is no restriction to the size that the array String can have
HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();

//initialize a key chosing the array of String you want for your values
map.put(1, new String[] { "name1", "name2" });

//edit value of a key
map.get(1)[0] = "othername";

Điều này rất đơn giản và hiệu quả. Nếu bạn muốn các giá trị của các lớp khác nhau thay vào đó, bạn có thể làm như sau:

HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();

0

Có thể được thực hiện bằng cách sử dụng một danh tínhHashMap, với điều kiện là việc so sánh các khóa sẽ được thực hiện bởi toán tử == và không bằng ().


0

Tôi thích cách sau để lưu trữ bất kỳ số lượng biến nào mà không phải tạo một lớp riêng.

final public static Map<String, Map<String, Float>> myMap    = new HashMap<String, Map<String, Float>>();

0

Tôi đã quá quen với việc chỉ làm điều này với Từ điển dữ liệu trong Mục tiêu C. Khó có được kết quả tương tự trong Java cho Android. Tôi đã kết thúc việc tạo một lớp tùy chỉnh, và sau đó chỉ thực hiện một hashmap của lớp tùy chỉnh của tôi.

public class Test1 {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.addview);

//create the datastring
    HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
    hm.put(1, new myClass("Car", "Small", 3000));
    hm.put(2, new myClass("Truck", "Large", 4000));
    hm.put(3, new myClass("Motorcycle", "Small", 1000));

//pull the datastring back for a specific item.
//also can edit the data using the set methods.  this just shows getting it for display.
    myClass test1 = hm.get(1);
    String testitem = test1.getItem();
    int testprice = test1.getPrice();
    Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}

//custom class.  You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
    private String item;
    private String type;
    private int price;

    public myClass(String itm, String ty, int pr){
        this.item = itm;
        this.price = pr;
        this.type = ty;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public String getType() {
        return item;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}


0

Sử dụng các bộ sưu tập Java

// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
                    .collect(Collectors.groupingBy(Employee::getDepartment));

Sở là chìa khóa của bạn ở đâu


-9

Hãy thử LinkedHashMap , mẫu:

Map<String,String> map = new LinkedHashMap<String,String>();    
map.put('1','linked');map.put('1','hash');    
map.put('2','map');map.put('3','java');.. 

đầu ra:

các phím: 1,1,2,3

các giá trị: được liên kết, hàm băm, bản đồ, java


7
Điều đó sẽ không làm việc. linkedsẽ không tồn tại trong bản đồ nữa vì bạn đã thay thế nó bằng hash.
Jeff Mercado
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.