HashMap z wieloma wartościami pod tym samym kluczem


199

Czy możemy zaimplementować HashMap z jednym kluczem i dwiema wartościami. Podobnie jak HashMap?

Proszę, pomóżcie mi również, mówiąc (jeśli nie ma innego sposobu), aby zaimplementować przechowywanie trzech wartości, z których jedna jest kluczem?



Dzięki przyjaciele ... ale mam pewne ograniczenia w korzystaniu z MultiHashMap
vidhya

Odpowiedzi:


266

Mógłbyś:

  1. Użyj mapy, która ma listę jako wartość. Map<KeyType, List<ValueType>>.
  2. Utwórz nową klasę opakowania i umieść instancje tego opakowania na mapie. Map<KeyType, WrapperType>.
  3. Użyj klasy krotkowej (oszczędza tworzenie wielu opakowań). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Korzystaj z wielu map obok siebie.

Przykłady

1. Mapa z listą jako wartością

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

Wadą tego podejścia jest to, że lista nie jest powiązana z dokładnie dwiema wartościami.

2. Korzystanie z klasy opakowania

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

Wadą tego podejścia jest to, że musisz napisać dużo kodu płyty kotłowej dla wszystkich tych bardzo prostych klas kontenerów.

3. Używanie krotki

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

To moim zdaniem najlepsze rozwiązanie.

4. Wiele map

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

Wadą tego rozwiązania jest to, że nie jest oczywiste, że dwie mapy są ze sobą powiązane, błąd programowy może spowodować, że dwie mapy nie zsynchronizują się.


Cześć Paul ... czy możesz to wyjaśnić ...? Na przykład ...?
vidhya

@vidhya: co szczególnie pasuje do twojego problemu? Czy twoje różnorodne obiekty są tego samego typu, czy innego?
Paul Ruane,

Przykład byłby świetny.
Xonatron

@Paul, dowolny prosty przykładowy kod dla nr 3 Map<KeyType, Tuple<Value1Type, Value2Type>>
Joarder Kamal

@CoolMind Jestem pewien, że ludzie mogą obejść błędy: a może mógłbyś je poprawić?
Paul Ruane

61

Nie, nie tylko jako HashMap. Zasadniczo potrzebujesz HashMapklucza od zbioru wartości.

Jeśli chcesz korzystać z bibliotek zewnętrznych, Guava ma dokładnie tę koncepcję w Multimapimplementacjach takich jak ArrayListMultimapi HashMultimap.


@ Jon, czy możesz podać działający przykład w Javie dla powyższego pytania zadanego przez OP. Bardzo doceniam, że możesz to opublikować
Deepak

2
@Deepak: Wyszukaj przykłady map guava, a znajdziesz przykładowy kod.
Jon Skeet,

1
@Deepak: Zasadniczo zbudowałbyś coś takiego jak ArrayListMultimapty ... lub po prostu używałbyś czegoś takiego HashMap<String, List<Integer>>. Zasadniczo musisz utworzyć pustą listę za każdym razem, gdy wartość jest dodawana po raz pierwszy.
Jon Skeet

1
czy masz działający przykładHashMap<String, List<Integer>>
Deepak,

9
@Deepak: Sugeruję, abyś sam spróbował stworzyć przykład, a jeśli utkniesz, zadaj pytanie, w tym kod, o ile masz. W ten sposób nauczysz się znacznie więcej.
Jon Skeet,

23

Innym dobrym wyborem jest użycie MultiValuedMap z Apache Commons. Spójrz na Wszystkie znane klasy implementacyjne u góry strony, aby uzyskać specjalistyczne implementacje.

Przykład:

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

można zastąpić

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

Więc,

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

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

spowoduje, że kolekcja będzie collzawierać „A”, „B” i „C”.


13

Spójrz na Multimapbiblioteki guava i jej implementację -HashMultimap

Kolekcja podobna do mapy, ale która może powiązać wiele wartości z jednym kluczem. Jeśli wywołasz put (K, V) dwa razy, z tym samym kluczem, ale różnymi wartościami, multimapa zawiera odwzorowania z klucza na obie wartości.


7

używam Map<KeyType, Object[]> do kojarzenia wielu wartości z kluczem na mapie. W ten sposób mogę przechowywać wiele wartości różnych typów powiązanych z kluczem. Musisz zachować ostrożność, zachowując odpowiednią kolejność wstawiania i pobierania z Object [].

Przykład: Rozważmy, że chcemy przechowywać informacje o studentach. Kluczem jest identyfikator, a my chcielibyśmy przechowywać imię i nazwisko, adres i adres e-mail powiązany z uczniem.

       //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
Dla mnie to najlepsza odpowiedź. Jest prostszy, bardziej zwięzły i mniej abstrakcyjny.
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

Dla przypomnienia, czystym rozwiązaniem JDK8 byłoby użycie Map::computemetody:

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

Jak na przykład

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

z wyjściem:

bar: foo
first: hello, foo, hello

Należy pamiętać, że w celu zapewnienia spójności w przypadku, gdy wiele wątków uzyskuje dostęp do tej struktury danych, ConcurrentHashMapi CopyOnWriteArrayListna przykład należy użyć.


Lepiej jest użyć computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
saka1029,

3

Jeśli korzystasz z Spring Framework . Jest:org.springframework.util.MultiValueMap .

Aby utworzyć niemodyfikowalną mapę wielu wartości:

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

Albo użyj org.springframework.util.LinkedMultiValueMap


2

Tak i nie. Rozwiązaniem jest zbudowanie klasy opakowania dla wartości, które zawierają 2 (3 lub więcej) wartości, które odpowiadają Twojemu kluczowi.



2

Najprostszym sposobem byłoby użycie biblioteki kolekcji 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
    }

}

link maven: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2

więcej na ten temat: 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);
}

Mam najlepsze wyniki.

Po prostu trzeba stworzyć nową HashMapodczuwalna

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

w twojej forpętli. Będzie to miało taki sam efekt jak ten sam klucz i wiele wartości.


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

Wynik:

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

      ["111"]

To jest biblioteka Google-Guava dla funkcji narzędziowych. To jest wymagane rozwiązanie.


To prawidłowe rozwiązanie i kilkakrotnie korzystałem z tego podejścia.
letowianka

tak, to działa, ale wyświetla dane w formacie [] mrówczanu Chcę te elementy jeden po drugim, jak je zablokować
Sunil Chaudhary

0

Nie mogłem opublikować odpowiedzi na komentarz Paula, dlatego tworzę nowy komentarz do Vidhya tutaj:

Opakowanie będzie SuperClassdla dwóch klas, które chcemy przechowywać jako wartość.

a wewnątrz klasy opakowania możemy umieścić powiązania jako obiekty zmiennej instancji dla dwóch obiektów klasy.

na przykład

class MyWrapper {

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

a w HashMap możemy to w ten sposób umieścić,

Map<KeyObject, WrapperObject> 

WrapperObj będzie miał zmienne klasowe:class1Obj, class2Obj


0

Możesz to zrobić niejawnie.

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

To jest bardzo proste i skuteczne. Jeśli zamiast tego chcesz wartości różnych klas, możesz wykonać następujące czynności:

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

0

Można to zrobić za pomocą tożsamościHashMap, pod warunkiem, że porównanie kluczy zostanie wykonane przez operator ==, a nie równa się ().


0

Wolę następujące do przechowywania dowolnej liczby zmiennych bez konieczności tworzenia osobnej klasy.

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

0

Jestem tak przyzwyczajony do robienia tego za pomocą Słownika danych w Celu C. Trudniej było uzyskać podobny wynik w Javie dla Androida. W końcu stworzyłem niestandardową klasę, a następnie po prostu wykonałem mapę mojej niestandardowej klasy.

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

Korzystanie z kolektorów Java

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

gdzie Departament jest twoim kluczem


-9

Wypróbuj LinkedHashMap , przykład:

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

wynik:

klucze: 1,1,2,3

wartości: połączone, skrót, mapa, java


7
To nie zadziała. linkednie będzie już istniał na mapie, ponieważ zastąpiłeś ją hash.
Jeff Mercado,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.