PEAT Online Course -
How To Improve Your Personal Performance in Java work Technology

  • YOU + CONTROL
  • Focus
  • Autonomy
  • Proficiency
  • Purpose
  • Covid-19!!!
  • Deep Hidden Meaning
  • FREE updates
GET 75% OFF NOW
Your Promo code: TECHLAYOFF
Exclusively on
VIMEO ON-DEMAND

Java Interview Answer Q2 – Duplicate Integers and Sort

27 March 2023 Comments off

4 minutes

683

Last week, I presented a Java Interview Question 2: How to Find Duplicate Integers and Sort? We had a test harness to find all duplicate integers in a list collection. We wanted a sorted set of integers as a String text output.

A modern Java solution is the following:

public class DuplicateIntegersFintechJobSoftwareTest {
 
     //...

    
     public String search_duplicates_sort_them(List<Integer> numberList) {

        var histogram = new HashMap<Integer, Integer>();
        numberList.stream().forEach(digit -> {
                    if (histogram.containsKey(digit)) {
                        histogram.put(digit, histogram.get(digit) + 1);
                    } else {
                        histogram.put(digit, 1);
                    }
                }
        );

        System.out.printf("histogram=%s\n", histogram);

        var duplicates = histogram.entrySet().stream().filter(
                tuple -> {
                    return tuple.getValue() > 1;
                }).map(tuple -> tuple.getKey()).sorted().toList();
        System.out.printf("duplicates=%s\n", duplicates);

        var buf = new StringBuilder();
        duplicates.stream().findFirst().ifPresent( x -> buf.append(x));
        duplicates.stream().skip(1).forEach( x -> buf.append(", "+x));

        System.out.printf(">>>> buf='%s'\n\n", buf.toString());
        return buf.toString();
    }

    //...
}

I coded against Java 19, however this code should work against Java 16. I am fairly sure the List.of(…) was introduced in 16.

Java Lambda functions can be complicated to interpret. So I say to code review submitter to subjectively ensure your code is readable weeks, if not months later. Break it down and use local variables to store stream results.

The first part of the function, builds a histogram of the input numbers. Remember in Java (Kotlin and Scala too), map collections are collection of Key-Value pairs. In Java, we call this pair EntrySet, in Kotlin and Scala, it is a Tuple of 2 elements.

var histogram = new HashMap<Integer, Integer>();
        numberList.stream().forEach(digit -> {
                    if (histogram.containsKey(digit)) {
                        histogram.put(digit, histogram.get(digit) + 1);
                    } else {
                        histogram.put(digit, 1);
                    }
                }
        );

In the above, for the input numberList we call the stream forEach() function in order build the histogram that represents the occurrances of a number. We get a map collection histogram={1=1, 2=1, 3=1, 4=2, 5=1, 6=1, 7=2, 8=1}

In the second step, we need to filter out the duplicates. We enumerate across the stream of entry sets, but this time in the histogram.

var duplicates = histogram.entrySet().stream().filter(
                tuple -> {
                    return tuple.getValue() > 1;
                }).map(tuple -> tuple.getKey()).sorted().toList();

In above, we filter for histogram values greater than one, or numbers that have more one occurance. The data type is EntrySet[Integer,Integer]. However, notice the second operation. After the filter() operation, we invoke a map() operation that converts the key (our number) into a single element Integer. Finally, a third operation, we call sorted() that sorts our final stream into ascending order then turns it into a list collection! Phew! List[Integer]

The third step does requires Java 16. For Scala and Kotlin folk this is very easy, because you know that lists can have head (x) and tail (xs), and it will be familiar. This is functional programming, properly.

We want to concatenate and join together elements in our final list collection. Here is the traditional way of writing this code:

       var buf = new StringBuilder();
       for (int i = 0; i < duplicates.size(); i++) {
            if (i != 0) {
                buf.append(", ");
            }
            buf.append(duplicates.get(i));
       }

Here is the Modern Java way of solving this:

        var buf = new StringBuilder();
        duplicates.stream().findFirst().ifPresent( x -> buf.append(x));
        duplicates.stream().skip(1).forEach( x -> buf.append(", "+x));
        return buf.toString()

The funky nearest equivalent to head() is Java, is invoke findFirst(), deal with the Optional<Integer>. We just append the first duplicate. The funky nearest equivalent to tail() in Java, is invoke skip(X), where X specifies the number of elements to skip over in the stream. We then enumerate across the rest of the stream. There is one more bit that I would clean up. return buf.toString(). I would remove the toString() call, because that is an implied Java language conversion. You see, olde school rapping dies hard!

That’s it.

Hope you enjoyed it. See you at the next lecture!

Peter Pilgrim

March 2023

I am open to work (Permanent or Contract)

Please read my linkedin profile for accurate information www.linkedin.com/in/peterpilgrim2000
and also my Github profile https://peterpilgrim.github.io/digital-cv/

Hey all! Thanks for visiting. I provide fringe benefits to interested readers: checkout consultancy, training or mentorship Please make enquiries by email or
call +44 (0)7397 067 658.

Due to the Off-Payroll Working plan for the UK government, I am enforcing stricter measures on contracts. All potential public sector GOV.UK contracts engagements must be approved by QDOS and/or SJD Accounting. Please enquire for further information.