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);
3
  • 3
    You should consider building yourself a Map<String, Integer> with ip as key and the total as value. Commented Oct 11, 2017 at 15:08
  • 7
    Or, better yet, a class with fields domain, ip and totalNumber and populate your list with that. Commented Oct 11, 2017 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. Commented Oct 11, 2017 at 16:24

1 Answer 1

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:

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your very detail explanation,have a nice day

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.