Bir HashMap'e yinelenen bir anahtar yerleştirildiğinde ne olur?


276

Ben aynı anahtar birden çok kez geçerseniz HashMapbireyin putyönteme ne orijinal değerine olur? Ya değer bile tekrarlarsa? Bununla ilgili herhangi bir belge bulamadım.

Durum 1: Bir anahtarın üzerine yazılan değerler

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
System.out.println(mymap.get("1"));

Anlıyoruz surely not one.

Durum 2: Yinelenen değer

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
// The following line was added:
mymap.put("1","one");
System.out.println(mymap.get("1"));

Anlıyoruz one.

Fakat diğer değerlere ne olur? Bir öğrenciye temel bilgiler veriyordum ve bunu istedim. MapBenzer bir değer, son değere başvuru yapılan bir kova mıdır (ancak bellekte)?


7
BTW, bu Jakarta koleksiyon sınıflarının bir parçası olan çoklu hasheti göstermek için mükemmel bir fırsattır ( commons.apache.org/collections ). İhtiyacınız olan zamanlar için aynı anahtarla ilişkili herhangi bir sayıda değere sahip olmanızı sağlar.
John Munsch

Yanıtlar:


303

Tanım olarak, putkomut, haritada verilen anahtarla ilişkili önceki değerin yerini alır (kavramsal olarak ilkel türler için bir dizi dizin oluşturma işlemi gibi).

Harita sadece değere olan referansını bırakır. Nesneye başka bir başvuru yoksa, bu nesne çöp toplama için uygun hale gelir. Ayrıca, Java, verilen anahtarla ilişkili herhangi bir önceki değeri döndürür (veya nullyoksa), böylece orada ne olduğunu belirleyebilir ve gerekirse bir referans tutabilirsiniz.

Daha fazla bilgi için: HashMap Doc


Bunun için teşekkürler. Java belgelerinden okunması, bundan açıkça bahsedilmez. Dokümanın yazarının, bunun tüm karma harita uygulamalarının örtük bir varsayımı olduğunu varsaydığını düşünüyorum.
Andrew S

77

Cevabınızı Harita # put (K, V) (aslında bir şey döndüren ) javadosunda bulabilirsiniz :

public V put(K key,
             V value)

Belirtilen değeri bu haritadaki belirtilen anahtarla ilişkilendirir (isteğe bağlı işlem). Harita daha önce bu anahtar için bir eşleme içeriyorsa, eski değer belirtilen değerle değiştirilir. (Bir haritanın yalnızca ve ancak geri dönecekse mbir anahtar için eşleme içerdiği söylenir .)km.containsKey(k)true

Parametreler:
key - belirtilen değerin ilişkilendirileceği anahtar.
value- belirtilen anahtarla ilişkilendirilecek değer.

Döndürür:
belirtilen anahtarla ilişkilendirilmiş veya nulleşleme yoksa önceki değer key. (Bir nulldönüş , uygulama değerleri destekliyorsa, daha önce nullbelirtilenle ilişkilendirilmiş haritanın da belirtilebilir .)keynull

Bu nedenle, arama yaparken döndürülen değeri atamazsanız, mymap.put("1", "a string")referans gösterilmez ve böylece çöp toplama için uygun hale gelir.


3
Döndürülen değer olduğunu önceki değeri (ya da nullöylesine, evet, bu ne demek sadece javadoc yukarıda belirtildiği gibi). Gerçekten yanlış yorumlanabilir mi?
Pascal Thivent

bu çok yardımcı.
roottraveller

18

Anahtar için önceki değer atılır ve yenisi ile değiştirilir.

Bir anahtarın verildiği tüm değerleri korumak isterseniz, bunun gibi bir şey uygulamayı düşünebilirsiniz:

import org.apache.commons.collections.MultiHashMap;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
public class MultiMapExample {

   public static void main(String[] args) {
      MultiHashMap mp=new MultiHashMap();
      mp.put("a", 10);
      mp.put("a", 11);
      mp.put("a", 12);
      mp.put("b", 13);
      mp.put("c", 14);
      mp.put("e", 15);
      List list = null;

      Set set = mp.entrySet();
      Iterator i = set.iterator();
      while(i.hasNext()) {
         Map.Entry me = (Map.Entry)i.next();
         list=(List)mp.get(me.getKey());

         for(int j=0;j<list.size();j++)
         {
          System.out.println(me.getKey()+": value :"+list.get(j));
         }
      }
   }
}

1
Bu çözüm karmaşıktır. MultiHashMap, java'nın değil apache.commons.collections öğesinin bir parçasıdır.
wikimix

17

Anahtar / Değer özelliğidir ve birkaç değer için yinelenen anahtarınız olamazdı, çünkü değerlerden hangisinin girilen anahtara ait gerçek değeri elde
etmek istediğinizde, örnekte "1" değerini almak istediğinizde o ?!
Bu, her değer için benzersiz bir tuşa sahip olmanızın nedenidir, ancak java standard lib tarafından bir numaraya sahip olabilirsiniz:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class DuplicateMap<K, V> {

    private Map<K, ArrayList<V>> m = new HashMap<>();

    public void put(K k, V v) {
        if (m.containsKey(k)) {
            m.get(k).add(v);
        } else {
            ArrayList<V> arr = new ArrayList<>();
            arr.add(v);
            m.put(k, arr);
        }
    }

     public ArrayList<V> get(K k) {
        return m.get(k);
    }

    public V get(K k, int index) {
        return m.get(k).size()-1 < index ? null : m.get(k).get(index);
    }
}


ve bu şekilde kullanabilirsiniz:

    public static void main(String[] args) {
    DuplicateMap<String,String> dm=new DuplicateMap<>();
    dm.put("1", "one");
    dm.put("1", "not one");
    dm.put("1", "surely not one");
    System.out.println(dm.get("1"));
    System.out.println(dm.get("1",1));
    System.out.println(dm.get("1", 5));
}

ve baskı sonuçları:

[one, not one, surely not one]
not one
null

Mükemmel cevap! aferin. Kelimenin tam anlamıyla programlama hayatımı kurtardın :).
Subin Babu

Benden de teşekkürler! Ben normal bir Harita ile aynı işlevselliği gerçekleştirmek için bir "Kaldır" yöntemi eklemek zorunda kaldım ama harika çalıştı!
JGlass

1
@JGlass hoş geldiniz dostum, ama bu teknik bir çözüm değil, java standart lib ile yapabileceğiniz şey budur, teknik olarak probleminizde sorununuzu izlemelisiniz, eğer bu davranışa ihtiyacınız varsa çözüm olmadığından eminim çünkü Anahtar / Değer kavramı ve sorun hakkında düşünmeli ve çözmenin mantıklı yolunu bulmalıdır. neyse benim ayrıntıları sadece java ile yapmak için eğlenceli bir yol ve üretim, sorunları ve çözüm yolu eğlenceli çalışmak için çok farklı! ancak Anahtar / Değer davranışı sizin probleminiz olmadığında ve böyle bir veri yapısına sahip olduğunuzda kullanabilirsiniz.
java acm

13

Belirtilen değeri bu haritadaki belirtilen anahtarla ilişkilendirir. Harita daha önce anahtar için bir eşleme içeriyorsa , eski değer değiştirilir.


12

Bu mevcut değerini değiştirir , ilgili anahtar için harita. Aynı ada sahip bir anahtar yoksa sağlanan değere sahip bir anahtar oluşturur. Örneğin:

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");

ÇIKIŞ tuşu = "1", değer = "iki"

Böylece, önceki değerin üzerine yazılır.


4

Haritanın bir kova gibi olup olmadığı sorunuza: hayır.

Bu bir dize olmak zorunda değil , name=valueçiftleri olan bir liste gibi name(olsa da, olabilir).

Bir öğe almak için anahtarınızı size atanan nesneyi veren get () - yöntemine iletirsiniz.

Ve bir Karma sen olsun yöntemi kullanarak nesneyi almak için çalışıyorsanız onun Listede yinelemek gerekiyor ve (karşılaştırmak istiyorsunuz, bunun nedeni), anahtar sağladığınız birine gerçek nesne karşılaştırmak olmaz haritası araçları geçerli öğeyi sağladınız.

Bu verimsiz olur. Bunun yerine, nesneniz ne olursa olsun, her iki nesneden de bir hashcode hesaplar ve bunları karşılaştırır. intİki tam (muhtemelen derinden karmaşık) nesne yerine iki s'yi karşılaştırmak daha kolaydır . Karma kodu önceden tanımlanmış bir uzunluğa (int) sahip bir özet gibi hayal edebilirsiniz, bu nedenle benzersiz değildir ve çarpışmalar vardır. Karma kodun kurallarını, bağlantıyı eklediğim belgelerde bulabilirsiniz.

Bununla ilgili daha fazla bilgi edinmek isterseniz, javapractices.com ve technofundo.com'daki makalelere göz atmak isteyebilirsiniz.

Saygılarımızla


3

Her zaman kullandım:

HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();

bir tanımlayıcı anahtara birden çok şey uygulamak isteseydim.

public void MultiHash(){
    HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
    String key = "Your key";

    ArrayList<String> yourarraylist = hashy.get(key);

    for(String valuessaved2key : yourarraylist){
        System.out.println(valuessaved2key);
    }

}

her zaman böyle bir şey yapabilir ve kendinize bir labirent oluşturabilirsiniz!

public void LOOK_AT_ALL_THESE_HASHMAPS(){
    HashMap<String, HashMap<String, HashMap<String, HashMap<String, String>>>> theultimatehashmap = new HashMap <String, HashMap<String, HashMap<String, HashMap<String, String>>>>();
    String ballsdeep_into_the_hashmap = theultimatehashmap.get("firststring").get("secondstring").get("thirdstring").get("forthstring");
}

2

JDK'daki haritalar, çoğaltılmış anahtarlar altında veri depolamak için tasarlanmamıştır.

  • En iyi yeni değer öncekileri geçersiz kılar.

  • Daha kötü senaryo istisnadır (örneğin bir akış olarak toplamaya çalıştığınızda):

Kopya yok:

Stream.of("one").collect(Collectors.toMap(x -> x, x -> x))

Tamam. Şunları elde edersiniz: $ 2 ==> {one = one}

Yinelenen akış:

Stream.of("one", "not one", "surely not one").collect(Collectors.toMap(x -> 1, x -> x))

İstisna java.lang.IllegalStateException: Yinelenen anahtar 1 (değerleri bir değil bir birleştirmeye çalıştı) | .duplicateKeyException (Collectors.java:133) | .lambda $ uniqKeysMapAccumulator $ 1'da (Collectors.java:180) | $ 3ReducingSink.accept (ReduceOps.java:169) konumunda | $ ArraySpliterator.forEachRemaining (Spliterators.java:948) | .copyInto (AbstractPipeline.java:484) | .wrapAndCopyInto (AbstractPipeline.java:474) | $ ReduceOp.evaluateSequential'da (ReduceOps.java:913) | .evaluate (AbstractPipeline.java:234) | ReferencePipeline.collect'da (ReferencePipeline.java:578) | (# 4: 1)

Yinelenen anahtarlarla başa çıkmak için - başka bir paket kullanın, örneğin: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html

Yinelenen anahtarlarla ilgili başka birçok uygulama var. Bunlar web için gereklidir (örneğin, yinelenen çerez anahtarları, Http başlıkları aynı alanlara sahip olabilir, ...)

İyi şanslar! :)


"geçersiz kılma" işlemi maliyetli midir?
gaurav

Yalnızca JDK kullanılarak çözülebilir. Collectors.toMap()üçüncü argüman - birleştirme işlevi vardır. Biz sadece son yinelenen eleman geçersiz kılmak isterseniz: Stream.of("one", "two", "one").collect(Collectors.toMap(x -> x, x -> x, (key1, key2) -> key2)). bağlantı
tek başına

Ayrıca ikinci kod örneğiniz doğru değil. Bu girdi: "one", "not one", "surely not one"tüm dizeler farklı olduğu için yinelenen anahtar hataları üretmez.
tek başına

Selam yalnız başıma. Lütfen haritalama fonksiyonunu (toMap) dikkatlice okuyun.
Witold Kaczurba

Merhaba @WitoldKaczurba. Lütfen göndermeden önce kodunuzu derleyin.
tek başına


1

Evet, bu, değeri olan 1 anahtarın tümünün son katma değerle üzerine yazıldığı ve burada "kesinlikle bir değil" eklediğiniz anlamına gelir, böylece yalnızca "kesinlikle bir değil" görüntüler.

Bir döngü ile görüntülemeye çalışsanız bile, aynı tuşa sahip yalnızca bir anahtar ve değer görüntüler.


0
         HashMap<Emp, Emp> empHashMap = new HashMap<Emp, Emp>();

         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp());
         empHashMap.put(new Emp(1), new Emp());
         System.out.println(empHashMap.size());
    }
}

class Emp{
    public Emp(){   
    }
    public Emp(int id){
        this.id = id;
    }
    public int id;
    @Override
    public boolean equals(Object obj) {
        return this.id == ((Emp)obj).id;
    }

    @Override
    public int hashCode() {
        return id;
    }
}


OUTPUT : is 1

Eşit ve hashCode () yöntemlerini doğru şekilde geçersiz kıldığınızda, karma harita yinelenenlere izin vermez.

HashSet ayrıca HashMap'i dahili olarak kullanır, kaynak dokümana bakın

public class HashSet{
public HashSet() {
        map = new HashMap<>();
    }
}
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.