从另一个列表更新列表

时间:2010-03-12 20:46:21

标签: java collections list-comprehension

我有一个本地商店中的用户列表,我需要每隔一段时间从远程用户列表中进行更新。基本上是:

  1. 如果本地已存在远程用户,请更新其字段。
  2. 如果本地尚不存在远程用户,请添加该用户。
  3. 如果本地用户未出现在远程列表中,请取消激活或删除。
  4. 如果本地用户也出现在远程列表中,请更新其字段。 (与1相同)
  5. EG。 远程列表:用户(1,真),用户(2,真),用户(4,真),用户(5,真)

    本地列表:用户(1,真),用户(2,假),用户(3,真),用户(6,真)

    新本地列表:用户(1,真),用户(2,真),用户(3,假),用户(4,真),用户(5,真),用户(6,假),< / p>

    只是同步本地列表的简单案例。有没有更好的方法在纯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 个答案:

答案 0 :(得分:7)

最好的方法是切换到不同的数据结构。 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.)如果本地尚不存在远程用户,请添加该用户。

查找来自User的{​​{1}} remoteUsers是否在localUsersO(1)O(log N)可以使用简单containsKey和{{ 1}}。

get
  

3.如果本地用户未出现在远程列表中,请取消激活或删除。

以下解决方案显示了这些更高级的数据结构的强大功能:

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

此外,如果您遇到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

答案 1 :(得分: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
    }
}

答案 2 :(得分:1)

Langali:

假设Id唯一标识用户,我会为您提供一些建议:

  • 创建一个User.Key类(User类的内部类),并将id字段移动到那里。让它成为最终的。使用id:
  • 覆盖User.Key类上的hashcode和equals方法
    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),这意味着当您将项目加倍时,将运算方法所需的时间乘以4。 HashMap的性能为O(log(n)),这意味着如果你有1000个对象,运行它所需的时间只会慢10倍(大约)。