Search code examples
javahashtable

Count how many pairs of a number appear in an array


Lets say with the array:

array = {1,2,1,2,1,3,2,1};

I want the output to be:

2 pairs of number 1, 1 pair of number 2

For that I created a Hash table. The code :

class Trail{
    static void countFreq(int arr[], int n)
    {
        Map<Integer, Integer> mp = new HashMap<>();
 
        // Insert elements into HashTable while avoiding overwriting:
        for (int i = 0; i < n; i++)
        {
            // This part is to avoid overwriting:
            if (mp.containsKey(arr[i]))
            {
                mp.put(arr[i], mp.get(arr[i]) + 1);
            }
            else
            {
                mp.put(arr[i], 1);
            }
        }
        // Traverse through map and print frequencies
        for (Map.Entry<Integer, Integer> entry : mp.entrySet())
        { 
            System.out.println(entry.getKey() + " " + entry.getValue());
            
        }
         
    }

    public static void main(String[] args) {

        int arr[] = {1,2,1,2,1,3,2,1};
        int n = arr.length;
        countFreq(arr, n);
    }
}

Not sure what to do next to print out the desired output. Been stuck in this simple part for a long time.


Solution

  • The calculation of frequencies seems to be fine, only printing part needs to be addressed. To get the number of pairs, divide the frequency by 2 (or shift right by 1), and skip if the pair count is 0 (according to the expected output).

    Printing should be moved into a separate method:

    static void printFreq(Map<Integer, Integer> mp) {
        boolean addComma = false;
        for (Map.Entry<Integer, Integer> entry : mp.entrySet()) {
            int pairs = entry.getValue() / 2;
            if (pairs < 1) {
                continue; // skip 0 pairs
            }
            if (addComma) {
                System.out.print(", ");
            }
            String p = pairs > 1 ? " pairs " : " pair ";
            System.out.print(pairs + p + "of number " + entry.getKey());
            addComma = true;
        }        
        System.out.println();    
    }
    

    However, Stream API may be used for such tasks:

    • use vararg int ... arr to pass the array of integer values in more convenient way (n as the array length is redundant)
    • use Collectors.groupingBy and Collectors.summingInt (or Collectors.counting) to calculate raw frequency
    • calculate the number of pairs
    • map each key-value pair into String
    • join the strings using Collectors.joining
    static void countFreq(int ... arr) {
        String message = Arrays.stream(arr)
            .boxed()
            .collect(Collectors.groupingBy(
                x -> x,
                Collectors.summingInt(x -> 1)
            )) // Map<Integer, Integer>
            .entrySet()
            .stream()
            .peek(e -> e.setValue(e.getValue() / 2))
            .filter(e -> e.getValue() > 0)
            .map(e -> String.format("%d %s of number %d", 
                e.getValue(), e.getValue() > 1 ? "pairs" : "pair", e.getKey()
            ))
            .collect(Collectors.joining(", "));
        System.out.println(message);
    }
    

    Output (in both cases):

    2 pairs of number 1, 1 pair of number 2