2011-09-10 71 views
2

審議關於與重複鍵存儲值以下問題:創建重複鍵地圖

  1. 假設有一個與名稱,SAL和DOB的屬性一類員工。我想將Employee的對象存儲在一個Map中,並且鍵將是Employee名稱。該名稱可以重複。

  2. 在Map中添加10個對象之後。我想檢索輸入的第8個對象。

This是一個解決方案添加對象有重複鍵,但對於問題的第二部分,這是行不通的,因爲上顯示地圖,使用相同的密鑰的所有值都會一起顯示。

在這種情況下,我們將如何保持對象的添加順序?我們是否可以修改equals和hashcode方法以某種方式添加元素,然後按照它們插入的順序檢索它們?

+0

您是否有興趣在所有輸入/員工或僅與衝突的鍵/名稱的那些的插入順序? – Gevorg

+0

2場景:1]假設我增加了10名全部具有相同密鑰和不同sal和dob的員工。 2] 10名僱員中的一些人有重複的鑰匙。在這兩種情況下,你將如何獲得地圖中的第n條記錄? –

+0

可能的重複http://stackoverflow.com/questions/1062960/map-implementation-with-duplicate-keys –

回答

0

這些要求在某種程度上是矛盾的。在一側,一個鍵可以有多個值,另一側只能返回一個鍵的值。另外,一個序列的檢索應該是可能的。我在設計專用數據結構時看到了最接近的近似值,該數據結構包含基於名稱的快速訪問哈希映射和保持插入順序的列表。訪問將基於總體序列號或名稱加上名稱索引。實施將按照以下線路是:

public class Employee { 
    public String name; public int sal;   
    public Employee() {name = ""; sal = 0;} 
    public Employee(String name, int sal) { 
     this.name = name; this.sal = sal; 
    } 
    @Override public String toString() {return "(" + name + "," + sal + ")";} 
} 

public class Team { 
    private Map<String, ArrayList<Employee>> employees = 
      new HashMap<String, ArrayList<Employee>>(); 
    private ArrayList<Employee> order = new ArrayList<Employee>(); 

    public void addEmployee(Employee e) { 
     ArrayList<Employee> list = employees.get(e.name);  
     if (list == null) { 
      list = new ArrayList<Employee>(); 
      employees.put(e.name, list); 
     } 
     list.add(e); 
     order.add(e); 
    }   
    public int getNumEmployees() {return order.size();} 
    public Employee getEmployee(int n) {return order.get(n - 1);}  
    public int getNumEmployees(String name) { 
     ArrayList<Employee> list = employees.get(name); 
     return list == null ? 0 : list.size(); 
    } 
    public Employee getEmployee(String name, int n) { 
     ArrayList<Employee> list = employees.get(name); 
     return list == null ? null : list.get(n - 1); 
    } 
} 

// Test: 
Team team = new Team(); 
team.addEmployee(new Employee("Bob", 11)); 
team.addEmployee(new Employee("Bob", 12)); 
team.addEmployee(new Employee("Eve", 13)); 
team.addEmployee(new Employee("Eve", 14)); 

System.out.println("Num all: " + team.getNumEmployees()); 
System.out.println("3rd: " + team.getEmployee(3)); 
System.out.println("Num Bobs: " + team.getNumEmployees("Bob")); 
System.out.println("2nd Bob: " + team.getEmployee("Bob", 2)); 
1

爲什麼不只是有兩個集裝箱?一個用於將名稱映射到員工(如stackoverflow question you mentioned中的名稱),另一個用於將員工映射到員工。你可以使一個「外部」容器聚合multimap和arraylist。

+0

不是太多的內存使用?受訪者表示可以通過修改equals和hashcode方法來實現,但我不知道如何... –

+0

@neeraj:好吧,它可以用hashcode完成,但我會說這將是一個醜陋的黑客攻擊。例如:在Empolyee中包含一個字段「hashcode」,初始化爲-1,在插入到散列表之前設置爲hashtable.size()。修改「Equals」,以便任何兩個員工如果不是同一個對象,就會有所不同。這應該做,但它很髒,並肯定會在代碼的其他部分出現一些問題。 – Vlad

1

您打算做什麼可以使用ArrayList輕鬆實現。這是您應該使用的數據結構。

+0

請你詳細說明......因爲我剛纔提到的例子使用了ArrayList,但是在顯示時,它將一起顯示具有相同鍵的對象,而不是它們在** Map **中插入的順序** –

+0

@neeraj我在說的是,也許你不需要一張地圖來滿足你的需求,只需將你的Employees添加到一個ArrayList。這將保持您將它們添加到列表中的順序。爲什麼你會問,爲什麼你需要這個案例的地圖? – Marcelo

+0

我不需要它,這是在採訪中被問到的。這只是一個場景......可能需要將值存儲在具有重複鍵的Map中...... –

2

我認爲LinkedHashMultimap(來自Guava)應該爲此工作。您無法直接通過索引獲得第8條,但您可以使用類似Iterables.get(Iterable iterable, int position)的內容來獲取它。

+0

這不能用java集合實現嗎?受訪者曾說過改變equals和hashcode的方法,但我不知道如何實現它... –

+0

@neeraj:好吧,LinkedHashMultimap基本上是一個LinkedHashMap >'plus一個'LinkedHashSet >'用於按添加的順序存儲條目。所以是的,您只能使用JDK類實現相同的效果。 – ColinD