'Hashmap values always being overwritten to last looped value

I cannot figure out why my HashMap keeps over writing all of my key/value pairs with the last ip address the method reads. Basically we are meant to store all of the ip addresses of website visitors on a particular day in an arraylist and then append this to a hashmap with the date being the key.

For some reason it keeps overwriting my values with the last value it reads.

Code:

public HashMap<String, String> visitorList(){

    HashMap<String, String> allIps = new HashMap<String, String>();
    for(LogEntry le : records)
    {
            String ipAddr = le.getIpAddress();
            String date = le.getAccessTime().toString();
            allIps.put(date, ipAddr);
    }
    System.out.println("All visitors: "+allIps);
    return allIps;
}



public HashMap<String, ArrayList<String>> iPsForDays(){
    ArrayList<String> ipsForDay = new ArrayList<String>();
    HashMap<String, ArrayList<String>> visOnDay = new HashMap<String, ArrayList<String>>();
    HashMap<String, String> allIps = visitorList();

    for(Map.Entry<String, String> entry : allIps.entrySet()){
            String key = entry.getKey().substring(4,7)+"-"+entry.getKey().substring(8,10);
            String value = entry.getValue();
//          visOnDay.put(key, ipsForDay);
            ipsForDay.clear();
            if(visOnDay.containsKey(key)){
                    ipsForDay = visOnDay.get(key);
                    System.out.println("VisOnDay array Value:" +ipsForDay);
                    ipsForDay.add(value);
                    System.out.println("+++++++++++++");
                    System.out.println("Current Values"+ipsForDay);
                    System.out.println("Current key: "+key);
                    System.out.println("+++++++++++++");
                    visOnDay.put(key, ipsForDay);
            }
            else{
                    System.out.println("____________");
                    System.out.println("Current key: "+key);
                    System.out.println("Currrent value: "+value);
                    System.out.println("____________");
                    ipsForDay.add(value);
                    visOnDay.put(key, ipsForDay);
                    System.out.println("VisOnDay initialisation: "+ visOnDay);
            }
//          visOnDay.put(key, ipsForDay);
    }
    System.out.println("Visitors on relevant days: "+visOnDay);
    return visOnDay;
}

The test file we are meant to use is as follows:

84.189.158.117 - - [21/Sep/2015:07:59:14 -0400] "GET /favicon.ico HTTP/1.0" 404 621
84.189.158.117 - - [30/Sep/2015:07:59:14 -0400] "GET /favicon.ico HTTP/1.0" 404 622
61.15.121.171 - - [21/Sep/2015:07:59:21 -0400] "GET /software.html HTTP/1.1" 200 1019
84.133.195.161 - - [14/Sep/2015:07:59:23 -0400] "GET /jflaptmp/ HTTP/1.1" 200 2708
84.133.195.161 - - [21/Sep/2015:07:59:23 -0400] "GET /images/New.gif HTTP/1.1" 200 390
84.133.195.161 - - [21/Sep/2015:07:59:30 -0400] "GET /jflaptmp/may15-2011/withoutSource/JFLAP.jar HTTP/1.1" 200 9781243
61.15.121.171 - - [30/Sep/2015:07:59:46 -0400] "GET /history.html HTTP/1.1" 200 1819
61.15.121.171 - - [30/Sep/2015:08:00:24 -0400] "GET /framebody.html HTTP/1.1" 200 3550
177.4.40.87 - - [30/Sep/2015:08:00:32 -0400] "GET / HTTP/1.1" 200 859
177.4.40.87 - - [30/Sep/2015:08:00:32 -0400] "GET /frameindex.html HTTP/1.1" 200 1127

Additionally the following are custom methods that are including in a file we were given with the homework assignment to assist with parsing files that contain the above data format.

import  java.util.*;
public class LogEntry {
     private String ipAddress;
     private Date accessTime;
     private String request;
     private int statusCode;
     private int bytesReturned;

     public LogEntry(String ip, Date time, String req, int status, int bytes) {
       ipAddress = ip;
       accessTime = time;
       request = req;
       statusCode = status;
       bytesReturned = bytes;

     }

     public String getIpAddress() {
         return ipAddress;
     }
     public Date getAccessTime() {
         return accessTime;
     }
     public String getRequest() {
         return request;
     }
     public int getStatusCode() {
         return statusCode;
     }
     public int getBytesReturned() {
         return bytesReturned;
     }

     public String toString() {
       return ipAddress + " " + accessTime + " " + request
           + " " + statusCode + " " + bytesReturned;
     }
}
import java.text.*;
import java.util.*;

public class WebLogParser {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy:kk:mm:ss Z", Locale.US);
    private static String munchTo(StringBuilder sb, String delim) {
        int x = sb.indexOf(delim);
        if (x == -1) {
            x = sb.length();
        }
        String ans = sb.substring(0,x);
        sb.delete(0, x + delim.length());
        return ans;
    }
    public static LogEntry parseEntry(String line) {
        //Assumes line is vald and in this format:
        //110.76.104.12 - - [30/Sep/2015:07:47:11 -0400] "GET //favicon.ico HTTP/1.1" 200 3426
        StringBuilder sb = new StringBuilder(line);
        String ip = munchTo(sb, " ");
        munchTo(sb, " "); //ignore -
        munchTo(sb, " ["); //ignore -, and eat the leading [
        String dateStr = munchTo(sb, "] \""); //]-space is intentional: eat both
        Date date = parseDate(dateStr);
        String request = munchTo(sb, "\" "); // quote-space is intentional: eat both
        String statusStr = munchTo(sb, " ");
        int status = Integer.parseInt(statusStr);
        String byteStr = munchTo(sb, " ");
        int bytes = Integer.parseInt(byteStr);
        return new LogEntry(ip, date, request, status, bytes);
    }
    public static Date parseDate(String dateStr) {
        ParsePosition pp = new ParsePosition(0);
        return  dateFormat.parse(dateStr, pp);
    }

}

To clarify the loop itself is not complete as I was trying to figure out why it was overwriting all of the key/values.



Solution 1:[1]

Under iPsForDays() method inside for(Map.Entry<String, String> entry : allIps.entrySet()){ you are reusing same reference of ipsForDay for inserting it into map.

Based on your requirement & hashmap declaration, you should create new list if its new key-value pair. For existing key , you have to retrive existing list , add new value into list & then put it back:

for(Map.Entry<String, String> entry : allIps.entrySet()){
            String key = entry.getKey().substring(4,7)+"-"+entry.getKey().substring(8,10);
            String value = entry.getValue();
            if(visOnDay.containsKey(key)){
                    System.out.println("+++++++++++++");
                    System.out.println("Current Values"+ipsForDay);
                    System.out.println("Current key: "+key);
                    System.out.println("+++++++++++++");
                    ArrayList<String> existingList=visOnDay.get(key);
                    existingList.add(value);
                    visOnDay.put(key, existingList);
            }
            else{
                    ArrayList<String> ipsForDay = new ArrayList<String>();
                    System.out.println("____________");
                    System.out.println("Current key: "+key);
                    System.out.println("Currrent value: "+value);
                    System.out.println("____________");
                    ipsForDay.add(value);
                    visOnDay.put(key, ipsForDay);
                    System.out.println("VisOnDay initialisation: "+ visOnDay);
            }

Also, remove ipsForDay Arraylist declaration which you have done at beginning of method iPsForDays , that is not required.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1