Refresh list from another list

I have a list of users in local storage that I need to periodically update from a remote list of users. Primarily:

  • If the remote user already exists locally, update its fields.
  • If the remote user does not already exist locally, add the user.
  • If the local user does not appear in the remote list, deactivate or delete.
  • If the local user also appears in the remote list, update its fields. (Same as 1)

Eg. Remote list: user (1, true), user (2, true), user (4, true), user (5, true)

Local list: user (1, true), user (2, false), user (3, true), user (6, true)

New local list: user (1, true), user (2, true), user (3, false), user (4, true), user (5, true), user (6, / p>

Just a simple example of local list synchronization. Is there a better way to do this in pure Java than the following? I feel rude looking at my own code.

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
source share
3 answers

The best way is to switch to another data structure. A Map<Integer, User>would be better because presumably users have unique identifiers. Your choice of implementation Mapcan be either HashMap(expected O(1)for basic operations) or TreeMap( O(log N)).

: @Override equals(Object) @Override hashCode()!!! ! , , ! (.: hashCode Java)

, , Map<Integer, User> remoteUsers Map<Integer, User> localUsers.

1.) , .
4.) , . ( , 1)
2.) , .

User remoteUsers localUsers O(1) O(log N) containsKey get.

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 -ed, Collections.binarySearch . Comparator<User> User implements Comparable<User>, id. O(N log N).

+6

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
    }
}
+1

Langali:

, Id , :

  • User.Key( User) id. . hashcode equals User.Key, id:
    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>
    ;
  • , , get containsKey, , .

The problem with List.contains is that ArrayList performs a full scan of the contents of the list. If you do this for each element of the second list, your performance is O (n ^ 2), which means that when you double the number of elements times four, the time it takes to run your method. HashMap has O (log (n)) performance, which means that if you have 1000 objects, the time it takes to run it is only 10 times slower (approximately).

+1
source

Source: https://habr.com/ru/post/1736717/


All Articles