Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Sunday, 8 June 2025

Nth highest salary from a given list using Java 8 Streams or second highest salary

 

Nth highest salary from a given list using Java 8 Streams. Below is a step-by-step program that demonstrates this using distinct sorting and skipping elements.


Java Program: Find the Nth Highest Salary


import java.util.Arrays;

import java.util.List;

import java.util.Optional;


public class NthHighestSalary {

    public static void main(String[] args) {

        List<Integer> salaries = Arrays.asList(50000, 60000, 75000, 40000, 75000, 90000, 60000);

        int n = 4; // Change this value to find the nth highest salary


        Optional<Integer> nthHighest = salaries.stream()

                .distinct() // Remove duplicate salaries

                .sorted((a, b) -> Integer.compare(b, a)) // Sort salaries in descending order

                .skip(n - 1) // Skip (n-1) highest salaries

                .findFirst(); // Get the nth highest salary


        System.out.println(n + "th highest salary: " + nthHighest.orElse(null));

    }

}


Exaplnation 

Create a list of salaries: Some salaries may be duplicate.


Use .stream(): Convert the list into a stream.


Remove duplicates: .distinct() ensures only unique salaries are considered.


Sort in descending order: .sorted((a, b) -> Integer.compare(b, a)) arranges salaries from highest to lowest.


Skip (n-1) highest salaries: .skip(n - 1) moves past the first (n-1) elements.


Get the next element: .findFirst() extracts the Nth highest salary.


Print the result: If the salary exists, it prints, otherwise null is returned




Second highest salary with given list


import java.util.Arrays;

import java.util.List;

import java.util.Optional;


public class SecondHighestNumber {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(12, 5, 8, 20, 15, 9, 20);


        Optional<Integer> secondHighest = numbers.stream()

                .distinct() // Remove duplicate numbers

                .sorted((a, b) -> Integer.compare(b, a)) // Sort in descending order

                .skip(1) // Skip the highest number

                .findFirst(); // Get the second highest


        System.out.println("Second highest number: " + secondHighest.orElse(null));

    }

}




2 ) 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;


public class SecondHighestNumber {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(12, 5, 8, 20, 15, 9, 20);


        Optional<Integer> highest = numbers.stream().max(Integer::compare);

        Optional<Integer> secondHighest = numbers.stream()

                .filter(num -> !num.equals(highest.orElse(null))) // Remove the highest

                .max(Integer::compare); // Find the second highest


        System.out.println("Second highest number: " + secondHighest.orElse(null));

    }

}




3 .


public class SecondHighestSalaryWithSet {

    public static void main(String[] args) {

        List<Employee> employees = Arrays.asList(

            new Employee("Alice", 50000),

            new Employee("Bob", 60000),

            new Employee("Charlie", 70000),

            new Employee("David", 80000),

            new Employee("Eve", 90000),

            new Employee("Frank", 90000) // Duplicate salary

        );


        // Find the second highest salary using a Set to eliminate duplicates

        Optional<Double> secondHighestSalary = employees.stream()

            .map(emp -> emp.salary)

            .collect(Collectors.toSet())               // Collect to a Set to remove duplicates

            .stream()

            .sorted(Comparator.reverseOrder())

            .skip(1)

            .findFirst();


        // Print the result

        System.out.println("Second Highest Salary: " + secondHighestSalary.orElse(-1));

    }

}






Collectors in java8 streams

 


Java 8’s Collectors class provides a suite of static methods for accumulating elements from a stream into collections, strings, maps, and more.


 Collectors are typically used with the Stream.collect() method, making it easy to process and transform data in a functional style.


Why:


Collectors provide ready-made solutions for common reduction operations, such as collecting stream elements into collections, grouping, partitioning, joining, and summarizing data. They make code concise, readable, and expressive.


When:


Use collectors when you want to gather, transform, group, or summarize data from a stream into a desired result format (e.g., List, Set, Map, or a single value).


Common Collectors and Their Use Cases


1. Collectors.toList()

When: 

When you want to collect stream elements into a List.


Example:

List<String> cities = Arrays.asList("Mumbai", "Delhi", "Bangalore", "Chennai");

List<String> cityList = cities.stream().collect(Collectors.toList());

System.out.println(cityList); // Output: [Mumbai, Delhi, Bangalore, Chennai]




Explanation:

Collects all stream elements into a List in encounter order


2. Collectors.toSet()

When:

When you need a Set (no duplicates) from stream elements.


Example:

List<String> cities = Arrays.asList("Mumbai", "Delhi", "Mumbai", "Bangalore");

Set<String> citySet = cities.stream().collect(Collectors.toSet());

System.out.println(citySet); // Output: [Mumbai, Delhi, Bangalore]


Explanation:

Removes duplicates by collecting elements into a Set



Thursday, 15 May 2025

Stream.iterate () vs iterate method

 


Stream.iterate() produces an infinite sequential stream in which each element is generated by applying a function (a unary operator) to the previous element. Because the stream is potentially unbounded, you almost always combine it with a terminal operation such as limit().


1. Generating a Sequence of Numbers

This example starts with zero and adds 1 for each subsequent element. We limit the stream to the first 10 elements.



import java.util.stream.Stream;


public class IterateBasicExample {

    public static void main(String[] args) {

        // Start at 0, with each subsequent element increased by 1.

        Stream<Integer> numbers = Stream.iterate(0, n -> n + 1);

        

        // Limit to the first 10 elements and print each number.

        numbers.limit(10).forEach(System.out::println);

    }

}



Explanation: Here, the initial element is 0. The lambda n -> n + 1 tells the stream to generate the next number by adding one to the current number. Since the stream is infinite, using limit(10) ensures that only 10 numbers are processed.


Output::

0

1

2

3

4

5

6

7

8

9



2 . Generating the Fibonacci Sequence

This example uses Stream.iterate() along with an array to generate pairs representing consecutive Fibonacci numbers. We then map these pairs to extract the first element in each pair (the Fibonacci number).


import java.util.stream.Stream;


public class FibonacciIterate {

    public static void main(String[] args) {

        // Each element in the stream is an array where:

        // - array[0] is the current Fibonacci number,

        // - array[1] is the next Fibonacci number.

        Stream.iterate(new long[]{0, 1}, pair -> new long[]{pair[1], pair[0] + pair[1]})

              .limit(10)              // Get the first 10 Fibonacci pairs.

              .map(pair -> pair[0])   // Extract the first number from each pair.

              .forEach(n -> System.out.print(n + " "));

    }

}



Explanation:


We start with the array {0, 1}.


The lambda pair -> new long[]{pair[1], pair[0] + pair[1]} computes the next Fibonacci pair.


We then limit the stream to 10 elements and map each array to its first element. This produces the Fibonacci numbers.


 Output::

0 1 1 2 3 5 8 13 21 34 


Stream.generate()

 Stream.generate() uses a given supplier (a function without arguments) to produce an infinite stream of values. Unlike iterate(), each new element is produced independently rather than based on the previous element.





1 . Generating a Constant Value

In this example, we create a stream that repeatedly outputs the same string. We then limit the stream so that only five copies are printed


import java.util.stream.Stream;


public class GenerateBasicExample {

    public static void main(String[] args) {

        // Generate a stream where each element is "Hello Java".

        Stream<String> constantStream = Stream.generate(() -> "Hello Java");

        

        // Limit the stream to 5 elements and print them.

        constantStream.limit(5).forEach(System.out::println);

    }

}



Explanation: The supplier (() -> "Hello Java") is called repeatedly to produce each element in the stream. The stream would be infinite if not for limit(5).



Output::

Hello Java

Hello Java

Hello Java

Hello Java

Hello Java



2 .

Generating Random Numbers

This example makes use of the built-in Math.random() method as a supplier to generate random numbers. Again, we limit the stream so it outputs a finite number of elements.


import java.util.stream.Stream;


public class RandomNumbersGenerate {

    public static void main(String[] args) {

        // Generate an infinite stream of random double values.

        Stream<Double> randomNumbers = Stream.generate(Math::random);

        

        // Limit to 5 random numbers and print each.

        randomNumbers.limit(5).forEach(System.out::println);

    }

}



Explanation: Math::random is a method reference that supplies a new random double (between 0.0 and 1.0) each time it is called. The stream is limited to 5 elements.


Output: The output will be 5 random double numbers, for example:

0.23744893145251387

0.8912345123451234

0.11234567890123456

0.6734523981274352

0.5493827459812739



Saturday, 5 April 2025

function identity () or identity method

 

Function.identity() Overview :

It is a static method in the  interface. It returns a function that accepts an input and returns the same input without any modifications. Essentially, it is a "no-op" function.

The  method in Java 8 is part of the functional programming features introduced with the java.util.function package. It is a static method in the  interface and is often used in scenarios where you need a function that simply returns its input, without making any changes or transformations.

Definition:

static <T> Function<T,T> identity()

Returns a function that always returns its input argument.

Type Parameters:

T - the type of the input and output objects to the function

Returns:

a function that always returns its input argument

static <T> Function<T, T> identity()

This method returns a function that always returns its input argument.

Purpose:

  1. It is a convenience method used when you don't want to apply any transformation to the input.
  2. Often used in streams or other functional operations where a function is required but no transformation is needed.

Key Characteristics:

  • Useful as a default or placeholder function.
  • The returned function is a "no-op" (no operation).

Why should we use it?
  1. No Transformation Needed: It's useful when you need a function but don't want to apply any transformation to the input.
  2. Code Simplification: Instead of writing a lambda expression like , you can use .
  3. Default/Placeholder Function: Acts as a default mapper or identity function in various operations

Example1 :
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "cherry");

        Map<String, String> map = list.stream()
            .collect(Collectors.toMap(Function.identity(), Function.identity()));

        System.out.println(map);
    }
}

Output:

{apple=apple, banana=banana, cherry=cherry}

Is t -> t same as Function.identity() method in Java?

import java.util.function.Function;

public class IdentityFunctionCompare {
    public static void main(String args[]) 
    {
        Function<Integer, Integer> funcIdentity = Function.identity();
        Function<Integer, Integer> funcIdentity1 = Function.identity();
        Function<Integer, Integer> funcIdentity2 = Function.identity();
        
        Function<Integer, Integer> intFuncMap1 = t -> t;
        Function<Integer, Integer> intFuncMap = t -> t;
        Function<Integer, Integer> intFuncMap = t -> t;
        
        System.out.println(funcIdentity);
        System.out.println(funcIdentity1);
        System.out.println(funcIdentity2);
        
        System.out.println(intFuncMap1);
        System.out.println(intFuncMap2);
        System.out.println(intFuncMap3);
    }
}


Output:
java.util.function.Function$$Lambda$1/0x0000000800034d78@b1d7fff
java.util.function.Function$$Lambda$1/0x0000000800034d78@b1d7fff
java.util.function.Function$$Lambda$1/0x0000000800034d78@b1d7fff
IdentityFunctionExample3$$Lambda$2/0x0000000800000a08@3e5c649
IdentityFunctionExample3$$Lambda$3/0x0000000800000c48@136432db
IdentityFunctionExample3$$Lambda$4/0x0000000800001000@6382f612



Saturday, 22 March 2025

Count Occurrences of zeros across number leading upto given number or given input

 

Find the occurrences of zero's for given input


1 )  package lrn.str1;


public class StrignClassDemo {


public static void main(String[] args) {

System.out.println("Total number counting zero's : " + countZerosInLeading(10));

}

private static int countZerosInLeading(int input) {

int count = 0;

for (int i = 0; i <= input; i++) {

if (isContainsZeros(i)) {

count++;

}

}

return count;

}


public static boolean isContainsZeros(int number) {

String data = Integer.toString(number);

return data.contains("0");

}

}


Output : Total number counting zero's : 2


2) 
package lrn.str1;

import java.util.stream.IntStream;

public class CountZerosInRange {

public static void main(String[] args) {
int input = 13;
System.out.println("Total number counting zero's : " + countNumbersWithZeros(input));
}

private static long countNumbersWithZeros(int input) {
return IntStream.rangeClosed(0, input).filter(CountZerosInRange::containsZero).count();
}

public static boolean containsZero(int n) {
return Integer.toString(n).contains("0");
}
}


output ::
Total number counting zero's : 2


Tuesday, 18 March 2025

Overview of Groupingby in Java8 streams

 Overview of groupingBy in Java 8 Streams

The groupingBy collector in Java 8 is part of the Collectors class and is used to group elements in a stream by a specified classifier function. It works similarly to the SQL GROUP BY statement, where data is categorized based on certain attributes. The result is typically a Map, where the keys are the grouping criteria, and the values are the grouped elements.


Steps to Use groupingBy

Prepare Your Data: Have a Collection or Stream of elements (e.g., a List of objects).


Stream Your Data: Convert your collection into a stream using .stream().


Group Elements:


Use Collectors.groupingBy() to specify how the elements should be grouped.


Optionally, apply downstream collectors for further aggregation (e.g., counting(), mapping()).


Examples 1 : Group by String length 


import java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.stream.Collectors;


public class GroupingByExample {

    public static void main(String[] args) {

        // Sample data

        List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");


        // Group words by their length

        Map<Integer, List<String>> groupedByLength = words.stream()

                .collect(Collectors.groupingBy(String::length));


        // Output the result

        System.out.println("Grouped by Length: " + groupedByLength);

    }

}

Output:

Grouped by Length: {3=[fig], 4=[date], 5=[apple, grape], 6=[banana, cherry]}


Explanation:


String::length is the classifier function that groups the words by their length.


The result is a Map where the key is the word length, and the value is a list of words with that length.


Exmaple 2: Group employee by department 


import java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.stream.Collectors;


class Employee {

    String name;

    String department;


    Employee(String name, String department) {

        this.name = name;

        this.department = department;

    }


    @Override

    public String toString() {

        return name;

    }

}


public class GroupingByExample {

    public static void main(String[] args) {

        // Sample data

        List<Employee> employees = Arrays.asList(

                new Employee("Alice", "HR"),

                new Employee("Bob", "IT"),

                new Employee("Charlie", "HR"),

                new Employee("David", "Finance"),

                new Employee("Eve", "IT")

        );


        // Group employees by department

        Map<String, List<Employee>> groupedByDepartment = employees.stream()

                .collect(Collectors.groupingBy(employee -> employee.department));


        // Output the result

        System.out.println("Grouped by Department: " + groupedByDepartment);

    }

}


output:

Grouped by Department: {Finance=[David], HR=[Alice, Charlie], IT=[Bob, Eve]}


Explanation:

The classifier function is employee -> employee.department, which groups employees by their department.


The result is a Map where the key is the department, and the value is a list of employees in that department.


Example 3: Group and Count Elements


import java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.stream.Collectors;


public class GroupingByCounting {

    public static void main(String[] args) {

        // Sample data

        List<String> items = Arrays.asList("apple", "banana", "apple", "orange", "banana", "apple");


        // Group and count occurrences

        Map<String, Long> itemCounts = items.stream()

                .collect(Collectors.groupingBy(item -> item, Collectors.counting()));


        // Output the result

        System.out.println("Item Counts: " + itemCounts);

    }

}


Output:

Item Counts: {orange=1, banana=2, apple=3}


Explanation:

The classifier function is item -> item, grouping elements by their value.


The downstream collector Collectors.counting() counts the occurrences of each group.


Key Features of groupingBy

Basic Grouping:


Groups elements based on a key or classifier.


E.g., Collectors.groupingBy(Function.identity()).


Downstream Collectors:


Apply further operations like counting, mapping, or reducing on the grouped elements.


Example: Collectors.groupingBy(key, Collectors.counting()).


Nested Grouping:


Group by multiple levels using nested groupingBy.


Example: Group employees by department and then by job title.


Custom Map Implementation:


Use the three-argument version of groupingBy to specify the type of Map to use for the result.



Nested grouping with groupingBy in Java 8 allows you to group elements by multiple levels. This involves creating a Map where each key corresponds to a group, and the value is another map representing the next level of grouping. Here’s how to achieve this with some examples:


Example 1: Group Employees by Department and then by Designation

java



Pimport java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.stream.Collectors;


class Employee {

    String name;

    String department;

    String designation;


    Employee(String name, String department, String designation) {

        this.name = name;

        this.department = department;

        this.designation = designation;

    }


    @Override

    public String toString() {

        return name;

    }

}


public class NestedGroupingExample {

    public static void main(String[] args) {

        // Sample data

        List<Employee> employees = Arrays.asList(

            new Employee("Alice", "HR", "Manager"),

            new Employee("Bob", "IT", "Developer"),

            new Employee("Charlie", "HR", "Executive"),

            new Employee("David", "IT", "Developer"),

            new Employee("Eve", "Finance", "Analyst")

        );


        // Nested grouping by department and then by designation

        Map<String, Map<String, List<Employee>>> groupedByDeptAndDesignation = employees.stream()

            .collect(Collectors.groupingBy(

                emp -> emp.department, // First level grouping: by department

                Collectors.groupingBy(

                    emp -> emp.designation // Second level grouping: by designation

                )

            ));


        // Print the result

        System.out.println("Grouped by Department and Designation: " + groupedByDeptAndDesignation);

    }

}

Output:


Grouped by Department and Designation: {

    HR={Manager=[Alice], Executive=[Charlie]},

    IT={Developer=[Bob, David]},

    Finance={Analyst=[Eve]}

}



Explanation:


The first groupingBy groups employees by their department.


The second groupingBy further groups employees by their designation within each department.


The result is a nested Map<String, Map<String, List<Employee>>>.


Example 2: Group Words by Length and then by Their Initial Character


import java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.stream.Collectors;


public class NestedGroupingWords {

    public static void main(String[] args) {

        // Sample data

        List<String> words = Arrays.asList("apple", "ant", "banana", "cherry", "cat", "dog", "dragonfruit");


        // Nested grouping by word length and then by the first character

        Map<Integer, Map<Character, List<String>>> groupedByLengthAndFirstChar = words.stream()

            .collect(Collectors.groupingBy(

                String::length, // First level grouping: by length of the word

                Collectors.groupingBy(

                    word -> word.charAt(0) // Second level grouping: by the first character

                )

            ));


        // Print the result

        System.out.println("Grouped by Length and First Character: " + groupedByLengthAndFirstChar);

    }

}

Output:


Grouped by Length and First Character: {

    3={a=[ant], c=[cat], d=[dog]},


    5={a=[apple]},

    6={b=[banana]},

    7={c=[cherry]},

    11={d=[dragonfruit]}

}

Explanation:


The first groupingBy groups words by their length.


The second groupingBy groups words within each length group by their first character.