0

I am looking a good way to sum up some specific data in my ArrayList based on certain condition, but I can't make it work as expected. My ArrayList contains the following data sequence Domain,IP,Total Number, for instance:

[gmail.com", "172.11.0.89", 1, gmail.com", "172.11.0.89", 60, "gmail.com", "192.168.0.66", 13] 

What I am try to do is to loop through the ArrayList and retrieve the IP address. After that, I will get the next index which is total number. I will check through the whole ArrayList for any similar IP. If I find a similar IP I will do the same thing and sum up the total number with previous total number. For example, The total number of 172.11.0.89 should contain 61 since 60+1 = 61.

But I am not getting that output. Here is my sample output:

[gmail.com", "172.11.0.89", 1, gmail.com", "172.11.0.89", 60, "gmail.com", "192.168.0.66", 13] 
The IP "172.11.0.89"
The IP "172.11.0.89"
The IP "192.168.0.66"
The Data in Final Data is :["172.11.0.89", 1, "172.11.0.89", 75, "172.11.0.89", 149, "192.168.0.66", 223]

This is my source code:

System.out.println(domainDailyData1);
for(int l = 1;l<domainDailyData1.size();l+=3)  // getting the total count 
  {
     String tempIP1 = domainDailyData1.get(l);
     System.out.println("The IP "+tempIP1);
     for(int e = 1;e<domainDailyData1.size();e+=3)
     {
         String tempIP2 = domainDailyData1.get(l);

          if(tempIP2.equals(tempIP1))
           {
              String str1 = domainDailyData1.get(e+1);

              int temp1 = Integer.parseInt(str1);
              num1 += temp1;
           }
     }
         FinalData1.add(tempIP1);
         FinalData1.add(String.valueOf(num1));

 }
   System.out.println("The Data in Final Data is :"+FinalData1);
Assafs
  • 3,257
  • 4
  • 26
  • 39
attack
  • 103
  • 1
  • 11
  • 3
    You should consider building yourself a Map with ip as key and the total as value. – OH GOD SPIDERS Oct 11 '17 at 15:08
  • 7
    Or, better yet, a class with fields `domain`, `ip` and `totalNumber` and populate your list with that. – jsheeran Oct 11 '17 at 15:10
  • You have a few errors in the code. num1 is not initialized with every loop call, and you wrote String tempIP2 = domainDailyData1.get(l); when it should be String tempIP2 = domainDailyData1.get(e); There are many better ways to handle this problem than trying to iterate through an ArrayList of values. – Assafs Oct 11 '17 at 16:24

1 Answers1

2

Fixing mistakes

As the comments mentioned, you forgot to initialise some variable. First of all, as you did not explicitly define in your code, I assume that FinaData1 is a List<String>.

  1. you forgot to initialise num1
  2. you need to remember that you already scan a specific ip address
  3. in your second for loop, you confused the iterator: you used get(l) instead of get(e). With get(l), you'll always have tempIP2.equals(tempIP1) = true as tempIP1 = domainDailyData1.get(l)

With correction, your code looks like:

public static void main(String... aArgs) {
   List<String> domainDailyData1 = Arrays.asList(new String[]{
        "gmail.com", "172.11.0.89", "1",
        "gmail.com", "172.11.0.89", "60",
        "gmail.com", "192.168.0.66", "13"});

    // >>> convention: don't use capital letter as the first letter of a variable
    List<String> finalData1 = new ArrayList<>();

    // getting the total count 
    for (int l = 1; l < domainDailyData1.size(); l += 3) {
        String tempIP1 = domainDailyData1.get(l);

        // 2. to avoid looping an IP that you already counted
        if (!finalData1.contains(tempIP1)) {
            
            System.out.println("The IP " + tempIP1);
            
            // 1. num1 initialisation
            int num1 = 0;
            
            for (int e = 1; e < domainDailyData1.size(); e += 3) {
                
                // 3. iterator confusion
                String tempIP2 = domainDailyData1.get(e);
                
                if (tempIP2.equals(tempIP1)) {
                    String str1 = domainDailyData1.get(e + 1);
                    int temp1 = Integer.parseInt(str1);
                    num1 += temp1;
                }
            }
            
            finalData1.add(tempIP1);
            finalData1.add(String.valueOf(num1));
        }
    }
    
    System.out.println("The Data in Final Data is :" + finalData1);
}

Tested with the input in the code.

Java stream: a bit more fun

If you happen to use Java 8, then you can play a bit with stream. The idea is to heavily rely on the fact that your list is always correctly ordered:

For any i in [0, list.size()], you have:

  • if i % 3 = 0 then you have the domain name

  • if i % 3 = 1 then you have the ip address (format does not matter)

  • if i % 3 = 2 then you have the visit count which is a proper integer

This also means that the list size is always a multiple of 3: list.size() % 3 = 0.

Consequently, I'll do as follow:

  1. find all ip address and group by it
  2. find the next element which is the view count and sum it

which gives:

public static void main(String... aArgs) {
    
    List<String> domainDailyData1 = Arrays.asList(new String[]{
        "gmail.com", "172.11.0.89", "1",
        "gmail.com", "172.11.0.89", "60",
        "gmail.com", "192.168.0.66", "13"});

    // Result is a map as it is a pairing <IpAddress, Count>
    Map<String, Integer> countMap = Stream
            // Start with index = 1 and then jump by step of 3                
            .iterate(1, i -> i + 3)
            // Get the number of ip address to scan. A row a basically the 
            // triplet {domain, ip address, count} as I defined for the input.
            //
            // Integer division: if list size is below 3, then the result is
            // 0 and nothing happens. If the list size is not a multiple of
            // 3, for example, 11, then the result is 3 and last rows (index
            // from 8 to 10) are ignored
            .limit(domainDailyData1.size() / 3)
            // optional line but if you want to know what's currently happening...
            .peek(i -> System.out.println("Checking IP Address: " + domainDailyData1.get(i)))
            // Result is a map as it is a pairing <IpAddress, Count>
            .collect(Collectors.toMap(
                    // The key is of course the ip address which is at 
                    // position i. What's nice with Map is that if a another
                    // identical ipaddress is found, the key are merged. That's
                    // why it is necessary to define a merge function
                    i -> domainDailyData1.get(i),
                    // fetch the count associated with index i. As one never
                    // trust unknown input, any invalid count means zero
                    i -> {
                        try {
                            // Just get the count. The i+1 is not supposed
                            // to trigger the ArrayOutOfBoundException as 
                            // guaranteed by the .limit() above
                            Integer count = Integer.parseInt(domainDailyData1.get(i + 1));
                            return count;
                        }
                        catch (NumberFormatException e) {
                            // silent exception catching but you can do
                            // anything here
                            return 0;
                        }
                    },
                    // If two ip addresses are found, just sum the count
                    // The static method reference form is Integer::sum
                    (oldCount, newCount) -> oldCount + newCount
                )
            );
    
    System.out.println(countMap);
}

If you want to copy paste for testing

  • without the explanation
  • and with static method reference
  • without the peek()
  • not map definition, directly print the result:

the code is:

public static void main(String... aArgs) {
    
    List<String> domainDailyData1 = Arrays.asList(new String[]{ "gmail.com", "172.11.0.89", "1", "gmail.com", "172.11.0.89", "60", "gmail.com", "192.168.0.66", "13"});
        
    Stream
        .iterate(1, i -> i + 3)
        .limit(domainDailyData1.size() / 3)
        .collect(Collectors.toMap(
                i -> domainDailyData1.get(i),
                i -> {
                    try {
                        return Integer.parseInt(domainDailyData1.get(i + 1));
                    }
                    catch (NumberFormatException e) {
                        return 0;
                    }
                },
                Integer::sum))
        .entrySet()
        .stream()
        .forEach(System.out::println);
}

This was rather for fun so this code may obviously not be 100% error-proof.


Source:

Community
  • 1
  • 1
Al-un
  • 3,102
  • 2
  • 21
  • 40