Aynı anahtarın altında birden çok değer içeren HashMap


199

Bir anahtar ve iki değer içeren bir HashMap uygulamamız mümkün mü? Tıpkı HashMap gibi mi?

Lütfen, üç değerin depolanmasını anahtar olarak bir tane ile gerçekleştirmenin başka bir yolunu (hiçbir yolu yoksa) söyleyerek bana yardımcı olun.



Teşekkürler arkadaşlar ... ama MultiHashMap kullanımında bazı sınırlamalar var
vidhya

Yanıtlar:


267

Yapabilirdiniz:

  1. Değer olarak listesi olan bir harita kullanın. Map<KeyType, List<ValueType>>.
  2. Yeni bir sarmalayıcı sınıfı oluşturun ve bu sarmalayıcının örneklerini haritaya yerleştirin. Map<KeyType, WrapperType>.
  3. Sınıf gibi bir demet kullanın (çok sayıda paket oluşturmayı kaydeder). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Çoklu haritaları yan yana kullanın.

Örnekler

1. Değer olarak liste ile eşleştirin

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

Bu yaklaşımın dezavantajı, listenin tam olarak iki değere bağlı olmamasıdır.

2. Sarıcı sınıfını kullanma

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

Bu yaklaşımın dezavantajı, tüm bu çok basit konteyner sınıfları için çok sayıda kazan plakası kodu yazmanız gerektiğidir.

3. Bir demet kullanma

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

Bence bu en iyi çözüm.

4. Birden fazla harita

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

Bu çözümün dezavantajı, iki haritanın ilişkili olduğu açık değildir, programlı bir hata iki haritanın senkronizasyondan çıktığını görebiliyordu.


Merhaba Paul ... bunu biraz daha açık hale getirebilir misin ...?
vidhya

@vidhya: hangisi özellikle probleminize uyuyor? Birden çok nesneniz aynı türde mi yoksa farklı mı?
Paul Ruane

Örnek aslında harika olurdu.
Xonatron

@ Paul, # 3 için herhangi bir basit örnek kod Map<KeyType, Tuple<Value1Type, Value2Type>>
Joarder Kamal

@CoolMind Eminim insanlar hatalar üzerinde kendi yollarını bulabilir: ya da belki onları düzeltebilirsiniz?
Paul Ruane

61

Hayır, sadece bir HashMap. Temelde HashMapbir anahtardan bir değer koleksiyonuna kadar bir anahtar gerekir .

Harici kütüphaneleri kullanmaktan memnunsanız, Guava ve Multimapgibi uygulamalarda tam olarak bu konsepte sahiptir .ArrayListMultimapHashMultimap


Jon @ yukarıdaki soru için Java örnek çalışma hacmiyle bunu yayınlamak eğer OP.Highly takdir tarafından sorulan sağlayabilir
Deepak

2
@Deepak: guava multimap örneklerini arayın, örnek kod bulacaksınız.
Jon Skeet

1
@Deepak: Temelde ArrayListMultimapkendin gibi bir şey inşa edeceksin ... ya da sadece bir HashMap<String, List<Integer>>ya da her neyse kullanacaksın . Temel olarak bir değer ilk eklendiğinde boş bir liste oluşturmanız gerekir.
Jon Skeet

1
için bir çalışma örneğiniz var mıHashMap<String, List<Integer>>
Deepak

9
@Deepak: Kendiniz bir örnek oluşturmayı denemenizi öneririm ve takılırsanız, kodunuzu içeren bir soru sorun. Bu şekilde çok daha fazla şey öğreneceksiniz.
Jon Skeet

23

Başka bir güzel seçenek de Apache Commons'tan MultiValuedMap kullanmaktır . Özel uygulamalar için sayfanın üst kısmındaki Bilinen Tüm Uygulama Sınıflarına bir göz atın .

Misal:

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

ile değiştirilebilir

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

Yani,

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

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

coll"A", "B" ve "C" içeren toplama ile sonuçlanacaktır .


13

MultimapGuava kütüphanelerinden ve uygulamasından bir göz atın -HashMultimap

Bir Haritaya benzer, ancak birden çok değeri tek bir anahtarla ilişkilendirebilen bir koleksiyon. Put (K, V) öğesini aynı anahtar ancak farklı değerlerle iki kez çağırırsanız, çoklu harita anahtardan her iki değere eşlemeler içerir.


7

Map<KeyType, Object[]>Birden çok değeri Haritadaki bir anahtarla ilişkilendirmek için kullanıyorum . Bu şekilde, bir anahtarla ilişkili farklı türde birden çok değer depolayabilirim. Nesne [] 'ye ekleme ve alma sırasını koruyarak dikkatli olmalısınız.

Örnek: Öğrenci bilgilerini saklamak istiyoruz. Anahtar id, ancak öğrenciyle ilişkili adı, adresi ve e-postayı saklamak istiyoruz.

       //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
Bana göre bu en iyi cevap. Daha basit, daha özlü ve daha az soyut.
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

Sadece kayıt için, saf JDK8 çözümü Map::computeyöntemi kullanmak olacaktır :

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

Gibi

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

çıktı ile:

bar: foo
first: hello, foo, hello

Birden çok iş parçacığının bu veri yapısına erişmesi ConcurrentHashMapve CopyOnWriteArrayListörneğin kullanılması gerektiğinde tutarlılığı sağlamak için unutmayın .


Kullanmak daha iyidir computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
saka1029

3

Eğer kullanırsanız Bahar Framework . Var:org.springframework.util.MultiValueMap .

Değiştirilemez çok değerli harita oluşturmak için:

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

Veya kullan org.springframework.util.LinkedMultiValueMap


2

Evet ve hayır. Çözüm, anahtarınıza karşılık gelen 2 (3 veya daha fazla) değeri içeren değerleriniz için bir Sarıcı clas oluşturmaktır.



2

En kolay yol, bir Google koleksiyon kitaplığı kullanmaktır:

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 bağlantısı: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2

bunun hakkında daha fazla bilgi: 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);
}

En iyi sonuçları aldım.

Sadece yeni HashMapgibi

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

senin içinde fordöngü. Aynı anahtar ve birden çok değer gibi aynı etkiye sahip olacaktır.


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

Çıktı:

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

      ["111"]

Bu, yardımcı işlevler için Google-Guava kütüphanesidir. Gerekli çözüm budur.


Bu geçerli bir çözüm ve bu yaklaşımı birkaç kez kullandım.
letowianka

Evet çalışıyor ama veri gösteren [] format ben nasıl bu pls im takılıp almak için bu öğeleri tek tek istiyorum
Sunil Chaudhary

0

Paul'un yorumuna bir cevap gönderemedim, bu yüzden burada Vidhya için yeni bir yorum oluşturuyorum:

Sarıcı bir SuperClass değer olarak saklamak istediğimiz iki sınıf için .

ve sarmalayıcı sınıfın içinde, ilişkilendirmeleri iki sınıf nesnesi için örnek değişken nesneleri olarak koyabiliriz.

Örneğin

class MyWrapper {

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

ve HashMap'e bu şekilde koyabiliriz,

Map<KeyObject, WrapperObject> 

WrapperObj sınıf değişkenlerine sahip olacaktır:class1Obj, class2Obj


0

Bunu dolaylı olarak yapabilirsiniz.

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

Bu çok basit ve etkilidir. Bunun yerine farklı sınıfların değerlerini istiyorsanız, aşağıdakileri yapabilirsiniz:

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

0

Anahtar karşılaştırmasının == operatörü tarafından yapılacağı ve eşittir () olmadığı koşuluna tabi bir identityHashMap kullanılarak yapılabilir.


0

Ayrı bir sınıf oluşturmak zorunda kalmadan istediğiniz sayıda değişkeni depolamak için aşağıdakileri tercih ederim.

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

0

Bunu sadece Amaç C'deki bir Veri Sözlüğü ile yapmaya alışkınım. Android için Java'da benzer bir sonuç almak daha zordu. Sonunda özel bir sınıf yarattım ve sonra sadece özel sınıfımın hashmap'ını yaptım.

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 Toplayıcıları Kullanma

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

Departman anahtarınızdır


-9

LinkedHashMap'ı deneyin , örnek:

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

çıktı:

tuşlar: 1,1,2,3

değerler: bağlantılı, karma, harita, java


7
Bu işe yaramaz. linkedartık haritada mevcut olmayacak, çünkü onun yerini hash.
Jeff Mercado
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.