HashMap з кількома значеннями під одним ключем


199

Чи можливо нам реалізувати HashMap з одним ключем і двома значеннями. Так само, як HashMap?

Будь ласка, допоможіть мені, також сказавши (якщо немає можливості) будь-який інший спосіб реалізувати зберігання трьох значень з одним як ключовим?



Дякую друзям ... але у мене є деякі обмеження у використанні MultiHashMap
vidhya

Можливий дублікат реалізації Map з повторюваними ключами
Стів Чемберс

Відповіді:


266

Ти міг:

  1. Використовуйте карту зі списком як значення. Map<KeyType, List<ValueType>>.
  2. Створіть новий клас обгортки та розмістіть екземпляри цієї обгортки на карті. Map<KeyType, WrapperType>.
  3. Використовуйте клас типу кортежу (економить, створюючи багато обгортки). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Використовуйте багатоядерні карти поруч.

Приклади

1. Карта зі списком як значення

// 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];

Недоліком такого підходу є те, що список не пов'язаний рівно з двома значеннями.

2. Використання класу обгортки

// 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;

Недоліком такого підходу є те, що для всіх цих дуже простих контейнерних класів потрібно написати багато кодових плит.

3. Використання кортежу

// 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;

На мій погляд, це найкраще рішення.

4. Кілька карт

// 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"];

Недоліком цього рішення є те, що не очевидно, що дві карти пов'язані, програмна помилка могла побачити, як дві карти виходять із синхронізації.


Привіт Пол, ти можеш зробити це трохи більш зрозумілим ...? Прикладом ...
vidhya

@vidhya: що зокрема відповідає вашій проблемі? Чи є ваші багатопрофільні об’єкти одного типу чи різними?
Пол Руан

Приклад був би чудово насправді.
Xonatron

@Paul, будь-який простий приклад коду №3 Map<KeyType, Tuple<Value1Type, Value2Type>>
Жоардер Камал,

@CoolMind Я впевнений, що люди можуть подолати помилки: чи ви могли їх виправити?
Пол Руан

61

Ні, не просто як HashMap. В основному вам знадобиться HashMapключ від набору значень.

Якщо ви раді використовувати зовнішні бібліотеки, Guava має саме цю концепцію в Multimapтаких реалізаціях, як ArrayListMultimapі HashMultimap.


@ Джон, НЕ могли б ви надати двухкомпонентной робочий приклад в Java для вище питання , поставлене OP.Highly вдячний , якщо ви могли б розмістити його
Діпак

2
@Deepak: Знайдіть приклади мультимапа гуави, і ви знайдете зразок коду.
Джон Скіт

1
@Deepak: В основному ви б створили щось на кшталт ArrayListMultimapсебе ... або просто скористаєтесь HashMap<String, List<Integer>>чи іншим. Потрібно створити порожній список будь-коли, коли значення додається вперше, в основному.
Джон Скіт

1
чи є у вас робочий прикладHashMap<String, List<Integer>>
Deepak

9
@Deepak: Я пропоную спробувати створити приклад самостійно, і якщо ви застрягли, задайте питання, що включає код, наскільки у вас є. Ви дізнаєтесь набагато більше таким чином.
Джон Скіт

23

Ще один приємний вибір - використовувати MultiValuedMap від Apache Commons. Ознайомтеся з усіма відомими класами впровадження у верхній частині сторінки для спеціалізованих реалізацій.

Приклад:

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

може бути замінено на

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

Так,

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

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

призведе до колекції, collщо містить "A", "B" і "C".


13

Ознайомтеся Multimapз бібліотеками guava та її реалізацією -HashMultimap

Колекція, схожа на Map, але яка може асоціювати кілька значень з одним ключем. Якщо ви викликаєте put (K, V) двічі, з одним і тим же ключем, але різними значеннями, мультимапа містить відображення від ключа до обох значень.


7

Я використовую Map<KeyType, Object[]>для об'єднання декількох значень з ключем на карті. Таким чином я можу зберігати кілька значень різних типів, пов’язаних з ключем. Ви повинні подбати, підтримуючи належний порядок вставки та вилучення з Object [].

Приклад. Поміркуйте, ми хочемо зберігати інформацію про студентів. Ключ - id, тоді як ми хотіли б зберегти ім'я, адресу та електронну пошту, пов’язані зі студентом.

       //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
Для мене це найкраща відповідь. Це простіше, більш стисло та менш абстрактно.
Морей


4

Тільки для запису, чистим рішенням JDK8 було б використовувати Map::computeметод:

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

Як от

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

з виходом:

bar: foo
first: hello, foo, hello

Зауважте, що для забезпечення узгодженості у випадку, якщо декілька потоків отримують доступ до цієї структури даних, ConcurrentHashMapі, CopyOnWriteArrayListнаприклад, їх потрібно використовувати.


Краще використовувати computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
saka1029

3

Якщо ви використовуєте Spring Framework . Існує: org.springframework.util.MultiValueMap.

Щоб створити незмінювану багатозначну карту:

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

Або використовувати org.springframework.util.LinkedMultiValueMap


2

Так і ні. Рішення полягає в створенні класу Wrapper для ваших значень, який містить 2 (3 або більше) значення, які відповідають вашому ключу.



2

Найпростішим способом було б користуватися бібліотекою колекцій 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
    }

}

maven посилання: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2

докладніше про це: 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);
}

У мене найкращі результати.

Вам просто потрібно створити нові HashMapподібні

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

у вашому forциклі. Це матиме такий же ефект, як і той самий ключ і кілька значень.


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

Вихід:

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

      ["111"]

Це бібліотека Google-Guava для корисних функцій. Це необхідне рішення.


Це вірне рішення, і я кілька разів використовував такий підхід.
letowianka

так, це працює, але він показує дані у форматі [], я хочу, щоб ті предмети один за іншим, як отримати цю програму, я застряг тут
Sunil Chaudhary

0

Я не зміг опублікувати відповідь на коментар Павла, тому я створюю тут новий коментар для Vidhya:

Wrapper буде SuperClassдля двох класів, які ми хочемо зберегти як значення.

і всередині класу обгортки ми можемо розмістити асоціації як об'єкти змінної інстанції для двох об'єктів класу.

напр

class MyWrapper {

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

і в HashMap ми можемо поставити таким чином,

Map<KeyObject, WrapperObject> 

У WrapperObj будуть змінні класу:class1Obj, class2Obj


0

Ви можете це робити неявно.

// 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";

Це дуже просто і ефективно. Якщо вам потрібні значення різних класів, ви можете зробити наступне:

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

0

Це можна зробити за допомогою ідентифікатораHashMap, за умови, що порівняння ключів буде виконано оператором ==, а не дорівнює ().


0

Я віддаю перевагу наступному, щоб зберігати будь-яку кількість змінних без необхідності створювати окремий клас.

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

0

Я так звик просто робити це зі словником даних в Objective C. Складніше отримати результат в Java для Android. Я в кінцевому підсумку створив спеціальний клас, а потім просто робив хешмап свого власного класу.

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

Використання Java Collectors

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

де відділ - ваш ключ


-9

Спробуйте LinkedHashMap , зразок:

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

вихід:

ключі: 1,1,2,3

значення: пов'язані, хеш, карта, java


7
Це не спрацює. linkedбільше не існуватиме на карті, оскільки ви її замінили на hash.
Джефф Меркадо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.