تنفيذ خريطة مع مفاتيح مكررة
-
21-08-2019 - |
سؤال
كنت تريد أن يكون لها خريطة مع مفاتيح مكررة.
أعرف أن هناك العديد من خريطة تطبيقات (الكسوف يظهر لي 50) لذا الرهان يجب أن يكون هناك واحد الذي يسمح بذلك.أعلم أنه من السهل الكتابة الخريطة الخاصة بك أن يفعل هذا, ولكن أود أن بدلا من استخدام بعض الحل الموجود.
ربما شيء في العموم مجموعات جوجل أو مجموعات ؟
المحلول
أنت تبحث عن multimap، والواقع على حد سواء المشاعات-مجموعات والجوافة لديهم عدة تطبيقات لذلك. Multimaps تسمح مفاتيح متعددة من خلال الحفاظ على مجموعة من القيم في مفتاح، أي يمكنك وضع كائن واحد في الخريطة، ولكن يمكنك استرجاع مجموعة.
إذا يمكنك استخدام جافا 5، وأود أن تفضل الجوافة و<لأ href = "https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Multimap.html "يختلط =" noreferrer "> Multimap
كما هو الوراثة علم.
نصائح أخرى
ونحن لسنا بحاجة إلى الاعتماد على مجموعات جوجل مكتبة خارجية. يمكنك ببساطة تطبيق خارطة التالية:
Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();
public static void main(String... arg) {
// Add data with duplicate keys
addValues("A", "a1");
addValues("A", "a2");
addValues("B", "b");
// View data.
Iterator it = hashMap.keySet().iterator();
ArrayList tempList = null;
while (it.hasNext()) {
String key = it.next().toString();
tempList = hashMap.get(key);
if (tempList != null) {
for (String value: tempList) {
System.out.println("Key : "+key+ " , Value : "+value);
}
}
}
}
private void addValues(String key, String value) {
ArrayList tempList = null;
if (hashMap.containsKey(key)) {
tempList = hashMap.get(key);
if(tempList == null)
tempList = new ArrayList();
tempList.add(value);
} else {
tempList = new ArrayList();
tempList.add(value);
}
hashMap.put(key,tempList);
}
يرجى التأكد من ضبط رمز.
Multimap<Integer, String> multimap = ArrayListMultimap.create();
multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");
multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");
multimap.put(3, "A");
System.out.println(multimap.get(1));
System.out.println(multimap.get(2));
System.out.println(multimap.get(3));
الناتج هو:
[A,B,C,A]
[A,B,C]
[A]
ملاحظة: نحن بحاجة إلى استيراد ملفات المكتبة.
http://www.java2s.com/Code/Jar/g/Downloadgooglecollectionsjar.htm
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
أو https://commons.apache.org/proper/commons-collections/download_collections.cgi
import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;
هل يمكن ببساطة تمرير مجموعة من القيم لقيمة في HashMap العادية، وبالتالي محاكاة مفاتيح مكررة، وسيكون متروك لكم لتقرر ما هي البيانات للاستخدام.
ويمكنك أيضا مجرد استخدام MultiMap ، على الرغم من أنني لا أحب فكرة مفاتيح مكررة نفسي.
إذا كنت تريد تكرار حول قائمة رئيسية ذات قيمة أزواج (كما كتب في التعليق)، ثم قائمة أو صفيف يجب أن يكون أفضل. الجمع بين أول المفاتيح والقيم الخاصة بك:
public class Pair
{
public Class1 key;
public Class2 value;
public Pair(Class1 key, Class2 value)
{
this.key = key;
this.value = value;
}
}
واستبدال CLASS1 وCLASS2 مع الأنواع التي تريد استخدامها للمفاتيح والقيم.
والآن يمكنك وضعها في صفيف أو قائمة وتكرار فوقها:
Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
...
}
commons.apache.org
MultiValueMap class
ويمكن حل هذه المشكلة مع قائمة خريطة دخول List<Map.Entry<K,V>>
. نحن لسنا بحاجة إلى استخدام المكتبات الخارجية لا ولا تطبيق جديد من الخريطة. يمكن إنشاء إدخال تعيين مثل هذا:
Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);
والتعلم من أخطائي ... من فضلك لا تنفيذ هذا بنفسك. الجوافة multimap هو الطريق للذهاب.
ووتعزيز المشترك المطلوبة في multimaps هو عدم السماح أزواج مكررة مفاتيح ذات قيمة.
وتنفيذ / تغيير هذا في التطبيق الخاص بك يمكن أن تكون مزعجة.
في الجوافة لها بسيطة مثل:
HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();
ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
وكان البديل يختلف قليلا من هذه المشكلة: كان مطلوبا لربط اثنين من قيم مختلفة مع نفس المفتاح. مجرد نشرها هنا في حال يساعد الآخرين، ولقد قدم HashMap كقيمة:
/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
@param innerMap: Key -> String (extIP), Value -> String
If the key exists, retrieve the stored HashMap innerMap
and put the constructed key, value pair
*/
if (frameTypeHash.containsKey(frameID)){
//Key exists, add the key/value to innerHashMap
HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
} else {
HashMap<String, String> innerMap = new HashMap<String, String>();
innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
// This means the key doesn't exists, adding it for the first time
frameTypeHash.put(frameID, innerMap );
}
}
في رمز أعلاه تتم قراءة frameID المفتاح من السلسلة الأولى من ملف الإدخال في كل سطر، هي التي شيدت قيمة frameTypeHash عن طريق تقسيم خط المتبقية وتخزينها وجوه سلسلة أصلا، على مدى فترة من الزمن بدأ الملف بعد خطوط متعددة (مع قيم مختلفة) مرتبطة مع مفتاح frameID نفسه، لذلك تم الكتابة frameTypeHash مع السطر الأخير كقيمة. أنا محل كائن سلسلة مع الكائن HashMap آخر كحقل قيمة، وهذا ساعد في الحفاظ على مفتاح واحد لرسم الخرائط قيمة مختلفة.
class DuplicateMap<K, V>
{
enum MapType
{
Hash,LinkedHash
}
int HashCode = 0;
Map<Key<K>,V> map = null;
DuplicateMap()
{
map = new HashMap<Key<K>,V>();
}
DuplicateMap( MapType maptype )
{
if ( maptype == MapType.Hash ) {
map = new HashMap<Key<K>,V>();
}
else if ( maptype == MapType.LinkedHash ) {
map = new LinkedHashMap<Key<K>,V>();
}
else
map = new HashMap<Key<K>,V>();
}
V put( K key, V value )
{
return map.put( new Key<K>( key , HashCode++ ), value );
}
void putAll( Map<K, V> map1 )
{
Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();
for ( Entry<K, V> entry : map1.entrySet() ) {
map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
}
map.putAll(map2);
}
Set<Entry<K, V>> entrySet()
{
Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
entry.add( new Entry<K, V>(){
private K Key = entry1.getKey().Key();
private V Value = entry1.getValue();
@Override
public K getKey() {
return Key;
}
@Override
public V getValue() {
return Value;
}
@Override
public V setValue(V value) {
return null;
}});
}
return entry;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{");
boolean FirstIteration = true;
for ( Entry<K, V> entry : entrySet() ) {
builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() ) );
FirstIteration = false;
}
builder.append("}");
return builder.toString();
}
class Key<K1>
{
K1 Key;
int HashCode;
public Key(K1 key, int hashCode) {
super();
Key = key;
HashCode = hashCode;
}
public K1 Key() {
return Key;
}
@Override
public String toString() {
return Key.toString() ;
}
@Override
public int hashCode() {
return HashCode;
}
}
هل يمكن أن يفسر أيضا السياق الذي تحاول تنفيذ خريطة مع مفاتيح مكررة؟ وأنا واثق يمكن أن يكون هناك حل أفضل. وتهدف خرائط للحفاظ على مفاتيح فريدة من نوعها لسبب وجيه. على الرغم من إذا كنت تريد حقا أن تفعل ذلك. يمكنك توسيع دائما الطبقة إرسال بريد مخصصة بسيطة خريطة الطبقة التي لديه وظيفة تخفيف الاصطدام وسوف تمكنك من الحفاظ مداخل متعددة مع نفس المفاتيح.
ملحوظة: يجب تنفيذ وظيفة تخفيف الاصطدام مثل ذلك، مفاتيح الاصطدام يتم تحويلها إلى مجموعة فريدة من نوعها "دائما". شيء بسيط مثل المفتاح مع شفرة التجزئة كائن أو شيء إلحاق؟
ولمجرد أن يكون كاملة، لديها أباتشي العموم مجموعات أيضا <لأ href = "http://commons.apache.org/collections/api-release/org/apache/commons/collections/MultiMap.html" يختلط = " نوفولو noreferrer "> MultiMap . الجانب السلبي بالطبع هو أن أباتشي العموم لا تستخدم الوراثة.
ومع قليل الإختراق التي يمكنك استخدامها HashSet مع مفاتيح مكررة. تحذير: هذا هو بشدة HashSet التنفيذ التابعة.
class MultiKeyPair {
Object key;
Object value;
public MultiKeyPair(Object key, Object value) {
this.key = key;
this.value = value;
}
@Override
public int hashCode() {
return key.hashCode();
}
}
class MultiKeyList extends MultiKeyPair {
ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();
public MultiKeyList(Object key) {
super(key, null);
}
@Override
public boolean equals(Object obj) {
list.add((MultiKeyPair) obj);
return false;
}
}
public static void main(String[] args) {
HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
set.add(new MultiKeyPair("A","a1"));
set.add(new MultiKeyPair("A","a2"));
set.add(new MultiKeyPair("B","b1"));
set.add(new MultiKeyPair("A","a3"));
MultiKeyList o = new MultiKeyList("A");
set.contains(o);
for (MultiKeyPair pair : o.list) {
System.out.println(pair.value);
}
}
وإذا كان هناك مفاتيح مكررة ثم مفتاح قد تتوافق مع أكثر من قيمة واحدة. الحل واضح هو لتعيين مفتاح قائمة من هذه القيم.
وعلى سبيل المثال في بيثون:
map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"] # It shows john and mike
print map["driver"][0] # It shows john
print map["driver"][1] # It shows mike
وأنا استخدم هذا:
وjava.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
1, Map<String, List<String>> map = new HashMap<>();
<اقتباس فقرة>
وهذا الحل مطول له عيوب متعددة ومعرضة للأخطاء. هذا يعني أننا في حاجة إلى مثيل كوكتيل لكل قيمة، وتحقق لل وجودها قبل إضافة أو إزالة قيمة، حذفه يدويا عندما لا يتم ترك القيم، إلى آخره.
اقتباس فقرة>2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface
وماذا عن مثل هذا impl MultiMap؟
public class MultiMap<K, V> extends HashMap<K, Set<V>> {
private static final long serialVersionUID = 1L;
private Map<K, Set<V>> innerMap = new HashMap<>();
public Set<V> put(K key, V value) {
Set<V> valuesOld = this.innerMap.get(key);
HashSet<V> valuesNewTotal = new HashSet<>();
if (valuesOld != null) {
valuesNewTotal.addAll(valuesOld);
}
valuesNewTotal.add(value);
this.innerMap.put(key, valuesNewTotal);
return valuesOld;
}
public void putAll(K key, Set<V> values) {
for (V value : values) {
put(key, value);
}
}
@Override
public Set<V> put(K key, Set<V> value) {
Set<V> valuesOld = this.innerMap.get(key);
putAll(key, value);
return valuesOld;
}
@Override
public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
K key = valueEntry.getKey();
Set<V> value = valueEntry.getValue();
putAll(key, value);
}
}
@Override
public Set<V> putIfAbsent(K key, Set<V> value) {
Set<V> valueOld = this.innerMap.get(key);
if (valueOld == null) {
putAll(key, value);
}
return valueOld;
}
@Override
public Set<V> get(Object key) {
return this.innerMap.get(key);
}
@Override
etc. etc. override all public methods size(), clear() .....
}