HashMap con più valori nella stessa chiave


199

È possibile per noi implementare una HashMap con una chiave e due valori. Proprio come HashMap?

Ti prego, aiutami, anche dicendo (se non c'è modo) un altro modo per implementare la memorizzazione di tre valori con uno come chiave?



Grazie amici ... ma ho alcune limitazioni nell'uso di MultiHashMap
vidhya,

Possibile duplicato dell'implementazione della mappa con chiavi duplicate
Steve Chambers

Risposte:


266

Potresti:

  1. Utilizzare una mappa con un elenco come valore. Map<KeyType, List<ValueType>>.
  2. Creare una nuova classe wrapper e posizionare le istanze di questo wrapper nella mappa. Map<KeyType, WrapperType>.
  3. Usa una classe simile a una tupla (salva la creazione di molti wrapper). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Usa le mappe multipla fianco a fianco.

Esempi

1. Mappa con elenco come valore

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

Lo svantaggio di questo approccio è che l'elenco non è associato esattamente a due valori.

2. Utilizzo della classe wrapper

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

Lo svantaggio di questo approccio è che devi scrivere un sacco di codice della piastra della caldaia per tutte queste classi di container molto semplici.

3. Usare una tupla

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

Questa è la migliore soluzione secondo me.

4. Mappe multiple

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

Lo svantaggio di questa soluzione è che non è ovvio che le due mappe siano correlate, un errore programmatico potrebbe vedere le due mappe non sincronizzate.


Ciao Paul ... puoi renderlo un po 'più chiaro ...? Con un esempio ...?
Vidhya,

@vidhya: quale in particolare si adatta al tuo problema? I tuoi oggetti mulitple sono dello stesso tipo o diversi?
Paul Ruane,

L'esempio sarebbe davvero fantastico.
Xonatron,

@Paul, qualsiasi semplice esempio di codice per # 3 Map<KeyType, Tuple<Value1Type, Value2Type>>
Joarder Kamal,

@CoolMind Sono sicuro che le persone possono aggirare gli errori: o potresti correggerli forse?
Paul Ruane,

61

No, non solo come a HashMap. Fondamentalmente avresti bisogno HashMapdi una chiave da una raccolta di valori.

Se sei felice di usare librerie esterne, Guava ha esattamente questo concetto Multimapcon implementazioni come ArrayListMultimape HashMultimap.


@ Jon, potresti fornirci un esempio funzionante in Java per la domanda di cui sopra fatta da OP. Ho molto apprezzato se tu potessi pubblicarla
Deepak,

2
@Deepak: cerca esempi multimap di guava e troverai un codice di esempio.
Jon Skeet,

1
@Deepak: Fondamentalmente costruiresti qualcosa di simile a ArrayListMultimapte ... o semplicemente usi un HashMap<String, List<Integer>>o qualunque cosa. Dovresti creare un elenco vuoto ogni volta che un valore viene aggiunto per la prima volta, in pratica.
Jon Skeet,

1
hai un esempio funzionante perHashMap<String, List<Integer>>
Deepak,

9
@Deepak: ti suggerisco di provare a creare un esempio tu stesso e, se rimani bloccato, fai una domanda includendo il codice per quanto hai. Imparerai molto di più in questo modo.
Jon Skeet,

23

Un'altra buona scelta è quella di utilizzare MultiValuedMap da Apache Commons. Dai un'occhiata alle Classi di implementazione All Known nella parte superiore della pagina per implementazioni specializzate.

Esempio:

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

potrebbe essere sostituito con

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

Così,

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

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

risulterebbe in una raccolta collcontenente "A", "B" e "C".


13

Dai un'occhiata alle Multimaplibrerie guava e alla sua implementazione -HashMultimap

Una raccolta simile a una mappa, ma che può associare più valori a una singola chiave. Se si chiama put (K, V) due volte, con la stessa chiave ma valori diversi, la multimappa contiene mappature dalla chiave su entrambi i valori.


7

Uso Map<KeyType, Object[]>per associare più valori a una chiave in una mappa. In questo modo, posso memorizzare più valori di diversi tipi associati a una chiave. Devi fare attenzione mantenendo l'ordine corretto di inserimento e recupero da Object [].

Esempio: considera che vogliamo archiviare le informazioni sugli studenti. Key is id, mentre vorremmo memorizzare il nome, l'indirizzo e l'e-mail associati allo studente.

       //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
Per me questa è la risposta migliore. È più semplice, più conciso e meno astratto.
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

Per la cronaca, la soluzione JDK8 pura sarebbe quella di utilizzare il Map::computemetodo:

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

Ad esempio

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

con uscita:

bar: foo
first: hello, foo, hello

Si noti che per garantire coerenza nel caso in cui più thread accedano a questa struttura di dati ConcurrentHashMape , CopyOnWriteArrayListad esempio, debbano essere utilizzati.


È meglio usare computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
saka1029,

3

Se si utilizza Spring Framework . C'è:org.springframework.util.MultiValueMap .

Per creare una mappa multi valore non modificabile:

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

Oppure usa org.springframework.util.LinkedMultiValueMap


2

Sì e no. La soluzione è creare un clac Wrapper per i tuoi valori che contenga i 2 (3 o più) valori che corrispondono alla tua chiave.



2

Il modo più semplice sarebbe utilizzare una libreria di raccolta 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
    }

}

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

altro su questo: 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);
}

Ho ottenuto i migliori risultati.

Devi solo creare un nuovo HashMaplike

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

nel tuo forciclo. Avrà lo stesso effetto della stessa chiave e più valori.


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

Produzione:

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

      ["111"]

Questa è la libreria Google-Guava per funzionalità di utilità. Questa è la soluzione richiesta.


È una soluzione valida e ho usato questo approccio in diverse occasioni.
letowianka,

sì, funziona ma mostra i dati nel formato [] voglio quegli elementi uno per uno come ottenere che i pls siano bloccati qui
Sunil Chaudhary

0

Non ho potuto pubblicare una risposta sul commento di Paul, quindi sto creando un nuovo commento per Vidhya qui:

Wrapper sarà a SuperClassper le due classi che vogliamo memorizzare come valore.

e all'interno della classe wrapper, possiamo mettere le associazioni come oggetti variabili di istanza per i due oggetti classe.

per esempio

class MyWrapper {

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

e in HashMap possiamo mettere in questo modo,

Map<KeyObject, WrapperObject> 

WrapperObj avrà variabili di classe:class1Obj, class2Obj


0

Puoi farlo implicitamente.

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

Questo è molto semplice ed efficace. Se si desidera invece valori di classi diverse, è possibile effettuare le seguenti operazioni:

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

0

Può essere eseguito utilizzando un identityHashMap, subordinatamente alla condizione che il confronto delle chiavi verrà eseguito dall'operatore == e non uguale a ().


0

Preferisco quanto segue per memorizzare un numero qualsiasi di variabili senza dover creare una classe separata.

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

0

Sono così abituato a farlo con un dizionario dei dati nell'obiettivo C. È stato più difficile ottenere un risultato simile in Java per Android. Ho finito per creare una classe personalizzata e poi semplicemente fare una hashmap della mia classe personalizzata.

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

Utilizzo di Java Collector

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

dove dipartimento è la tua chiave


-9

Prova LinkedHashMap , esempio:

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

produzione:

chiavi: 1,1,2,3

valori: collegato, hash, mappa, java


7
Non funzionerà linkednon esisterà più nella mappa perché è stato sostituito con hash.
Jeff Mercado,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.