2016-04-23 17 views
2

ich ein Mock Twitter Projekt erschaffe, die ~ 3,6 Millionen Zeilen wie diese formatiert enthält Benutzerdaten von einer etwas großen Textdatei lädt:Effiziente Objektinitialisierung

0 12 
0 32 
1 9 
1 54 
2 33 
etc... 

Der erste String-Token ist die userId und die zweite ist die followId.

Die erste Hälfte dieser Hilfsmethode nimmt die ID des aktuellen Benutzers auf, prüft, ob sie existiert, und erstellt bei Bedarf einen neuen Benutzer. Danach wird die followId der folgenden Liste des neuen oder vorhandenen Benutzers des Typs ArrayList<Integer> hinzugefügt.

Mit ~ 3,6 Millionen Zeilen zu lesen, dauert dies nicht lange (9868 ms).

Nun ist die zweite Hälfte schafft oder findet den gefolgten Benutzer (followId) und fügt die userId ihre Anhänger Listen, aber dieser zusätzliche Code erweitert die Menge der Zeit exponentiell die Datei zu lesen (172.744 ms).

Ich versuchte mit dem gleichen TwitterUser Objekt während der gesamten Methode. Alle Addiermethoden (follow, addFollower) sind einfache ArrayList.add() Methoden. Kann ich etwas tun, um diese Methode effizienter zu machen?

Bitte beachten Sie: Während dies Schule-bezogen ist, frage ich nicht nach einer Antwort auf meine Lösung. Mein Professor hat diese langsame Objektinitialisierung erlaubt, aber ich würde gerne verstehen, wie ich es schneller machen kann.

private Map<Integer, TwitterUser> twitterUsers = new HashMap<Integer, TwitterUser>(); 

private void AddUser(int userId, int followId){ 
    TwitterUser user = getUser(userId); 
    if (user == null){ 
     user = new TwitterUser(userId); 
     user.follow(followId); 
     twitterUsers.putIfAbsent(userId, user); 
    } else{ 
     user.follow(followId); 
    } 
    //adding the code below, slows the whole process enormously 
    user = getUser(followId); 
    if (user == null){      
     user = new TwitterUser(followId); 
     user.addFollower(userId); 
     twitterUsers.putIfAbsent(followId, user); 
    } else{ 
     user.addFollower(userId); 
    } 
} 

private TwitterUser getUser(int id){ 
    if (twitterUsers.isEmpty()) return null; 
    return twitterUsers.get(id); 
} 
+1

Sie müssen nicht überprüfen, ob 'twitterUsers.isEmpty()' in '# getUser',' Map # get' gibt 'null' zurück, wenn der angegebene Schlüssel nicht gefunden wird. Dies wird die Laufzeit nicht wesentlich reduzieren, aber es ist redundant. Könnten Sie auch den Code "TwitterUser # follow" und "TwitterUser # addFollower" posten? –

+0

gut, wenn 'PutIfAbsent' ist eine HashMap-Methode und' folgen' ist einfach: 1.) überprüfen, ob! ArrayList.contains (int) ... 2.) ArrayList.add (int) @JonnyHenly – terbubbs

+0

guten Punkt über die 'isEmpty() 'check .. albern von mir – terbubbs

Antwort

3

Wenn putIfAbsent(int, User) tut, was man erwarten würde es zu tun, das heißt: prüft wird, ob es da ist, bevor Einfügen, warum verwenden Sie es innerhalb eines if Block, dessen Zustand bereits überprüft, ob der Benutzer gibt es?

Mit anderen Worten, wenn das Holen eines Benutzers einen null Wert zurückgab, können Sie sicher annehmen, dass der Benutzer nicht dort war.

Jetzt bin ich nicht so sicher über die interne Funktionsweise der *putIfAbsent* Methode (wahrscheinlich würde es durch die Menge der Schlüssel in der Karte durchlaufen), aber intuitiv würde ich erwarten, eine normale put(int, User) besser, noch mehr mit eine Karte, die so groß wird wie Ihre, während die Eingabedatei gescannt wird.

Daher würde ich vorschlagen, so etwas wie versuchen:

user = getUser(followId); 
if (user == null){      
    user = new TwitterUser(followId); 
    user.addFollower(userId); 
    twitterUsers.put(followId, user); 
} else{ 
    user.addFollower(userId); 
} 

, die auch auf die erste Hälfte gelten würde.