2010-03-12 43 views
3

我有一個本地存儲中的用戶列表,我需要每隔一段時間從遠程用戶列表更新一次。基本上:從另一個列表更新列表

  1. 如果遠程用戶本地已存在,請更新其字段。
  2. 如果遠程用戶本地不存在,請添加該用戶。
  3. 如果本地用戶未出現在遠程列表中,請停用或刪除。
  4. 如果本地用戶也出現在遠程列表中,請更新其字段。 (與1相同)

例如, 遠程列表:用戶(1,真),用戶(2,真),用戶(4,真),用戶(5,真)

本地列表:用戶(1,true),用戶),User(3,true),User(6,true)

新本地列表:User(1,true),User(2,true),User(3,false),User(4,true) ,User(5,true),User(6,false),

只是一個簡單的同步本地列表的情況。有沒有更好的方式在純Java中做到這一點比以下更好?我感到很看重我自己的代碼。

public class User { 
    Integer id; 
    String email; 
    boolean active; 

    //Getters and Setters....... 

    public User(Integer id, String email, boolean active) { 
     this.id = id; 
     this.email = email; 
     this.active = active; 
    } 

    @Override 
    public boolean equals(Object other) { 
     boolean result = false; 
     if (other instanceof User) { 
      User that = (User) other; 
      result = (this.getId() == that.getId()); 
     } 
     return result; 
    } 

} 




public static void main(String[] args) { 

    //From 3rd party 
    List<User> remoteUsers = getRemoteUsers(); 

    //From Local store 
    List<User> localUsers =getLocalUsers();  

    for (User remoteUser : remoteUsers) { 
     boolean found = false; 
     for (User localUser : localUsers) { 
      if (remoteUser.equals(localUser)) { 
       found = true; 
       localUser.setActive(remoteUser.isActive()); 
       localUser.setEmail(remoteUser.getEmail()); 
       //update 
      } 
      break; 
     } 
     if (!found) { 
      User user = new User(remoteUser.getId(), remoteUser.getEmail(), remoteUser.isActive()); 
      //Save 
     } 
    } 

    for(User localUser : localUsers) { 
     boolean found = false; 
     for(User remoteUser : remoteUsers) { 
      if(localUser.equals(remoteUser)) { 
       found = true; 
       localUser.setActive(remoteUser.isActive()); 
       localUser.setEmail(remoteUser.getEmail()); 
       //Update 
      } 
      break; 
     } 
     if(!found) { 
      localUser.setActive(false); 
      // Deactivate 
     } 
    } 
} 
+3

1和4只能做一次,它們是相同的東西 – Lombo

+0

你可以提取一些方法(比如在用戶類中的'update(User user)',它將'user'的字段設置爲'this ')。你也可以在內部使用'java.util.Collections.binarySearch(list,user)'來理解。 – incarnate

回答

6

,最好的辦法是切換到不同的數據結構。 A Map<Integer, User>將是最好的,因爲大概用戶具有唯一標識ID。您選擇的Map實現可以是HashMap(對於基本操作預期爲O(1))或TreeMapO(log N))。

重要提示:您@Override equals(Object)沒有@Override hashCode() !!!這是危險!你應該總是養成兩種或兩種都不適合的習慣! (請參閱: Overriding equals and hashCode in Java

因此,假設您有Map<Integer, User> remoteUsersMap<Integer, User> localUsers

1)如果遠程用戶已經本地存在,更新它的字段。
4.)如果本地用戶也出現在遠程列表中,請更新其字段。 (與1相同)
2.)如果遠程用戶本地不存在,請添加用戶。

發現,如果從remoteUsers一個UserlocalUsers可以O(1)O(log N)來回答一個簡單的containsKeyget

for (int id : remoteUsers.keys()) { 
    User local; 
    if (localUsers.containsKey(id)) { 
     local = localUsers.get(id); 
    else { 
     localUsers.put(id, local = new User(id)); 
    } 
    local.updateFrom(remoteUsers.get(id)); 
} 

3)如果本地用戶沒有出現在遙控器列表,關閉或刪除。

以下解決方案顯示了這些更高級的數據結構的強大功能是:

Set<Integer> toDeactivate = new TreeSet<Integer>(); 
toDeactivate.addAll(localUsers.keySet()); 
toDeactivate.removeAll(remoteUsers.keySet()); 

for (int id : toDeactivate) { 
    User local = localUsers.get(id); 
    local.deactivate(); 
    localUsers.remove(id); 
} 

此外,如果你被卡住List<User>,你仍然可以使用Map<Integer, User>作爲中介的數據結構這個處理(基本上變換List<User>Map<Integer, User>然後回到List<User>)。它會更快,因爲它是O(N log N)O(N),而你現在的O(N^2)

如果你堅持只使用列表,那麼你可能想看看它是一個Collections.sort的列表,所以你可以做一個Collections.binarySearch就可以了。您需要提供一個Comparator<User>,或者製作User implements Comparable<User>,由id自然排序。這也將是O(N log N)

+0

它不總是可以在'List'和'Set'之間切換。它取決於領域模型。 – incarnate

+0

您仍然可以使用'Set'作爲中介。與O(N^2)相反,它的速度更快,因爲它是'O(N)'或'O(N log N)'。 – polygenelubricants

+0

請參閱上面的行:local = localUsers.get(remote); list.get只需要一個不是Obj的整數索引。 – Langali

1

你可以使用List.indexOf()而不是通過列表迭代:

for (User remoteUser : remoteUsers) { 
    int index = localUsers.indexOf(remoteUser); 
    if (index >= 0) { 
     User localUser = localUsers.get(index); 
     localUser.setActive(remoteUser.isActive()); 
     localUser.setEmail(remoteUser.getEmail()); 
     //update 
    } else { 
     User user = new User(remoteUser.getId(), remoteUser.getEmail(), remoteUser.isActive()); 
     //Save 
    } 
} 
+0

但是如果沒有列表理解或迭代,我如何獲取更新參數? – Langali

+0

變量localUser未定義? – Langali

+0

@Langali哎呀,好點。查看我的更新。 –

1

Langali:

假設ID唯一標識一個用戶,我有幾個建議供您參考:

  • 創建一個類User.Key(一個內部類User類的),和將id字段移到那裏。做最後的決定。重寫哈希代碼,只是使用id equals方法對User.Key類:
 
    public User { 
     private final Key key; 
     ... other variables 

     public static class Key { 
     private final int id; 
      public Key(final int id) { 

      } 
      // hashcode (can be the id) 
      // equals (as you had implemented) 
     } 
    } 
  • 創建映射握住你的用戶。
    Map<User.Key, User>
    ;
  • 使用此地圖來保存您的用戶,然後使用getcontainsKey方法找到您要查找的內容。

List.contains的問題是,在ArrayList上,它執行列表內容的完整掃描。如果您爲第二個列表中的每個項目執行此操作,則您的性能爲O(n^2),這意味着當您將項目翻倍時,將乘以四倍運行該方法所需的時間。 HashMap具有O(log(n))的性能,這意味着如果您有1000個對象,運行它所需的時間只有10倍左右(大約)。