Does Comparator Use Contains? A Comprehensive Guide

Does comparator use contains? This is a question that delves into the functionalities of comparators, especially within programming and electronic contexts, and this comprehensive guide on compare.edu.vn aims to clarify that, providing clear insights and actionable knowledge to enhance understanding. We’ll explore comparators and their uses to guide you through the decision-making process effectively. This detailed examination includes comparator logic, comparator circuits, and comparator design, all tailored for clarity and ease of understanding.

1. What is a Comparator?

A comparator is a fundamental electronic component or software function that compares two inputs (voltages or data) and outputs a binary signal indicating which input is larger or if the two inputs are equal. In electronics, it’s commonly implemented using op-amps or specialized comparator ICs. In programming, a comparator is a function or object that defines a comparison method, used for sorting or searching data structures. Comparators are vital for decision-making in embedded systems, control circuits, and data processing algorithms.

2. How Does a Comparator Work in Electronics?

Electronic comparators are built to deliver precise voltage comparisons, typically utilizing operational amplifiers (op-amps) in an open-loop configuration to maximize their gain and sensitivity.

  • Basic Operation: A comparator takes two input voltages, usually labeled as V+ (non-inverting input) and V- (inverting input). It compares these voltages and produces an output voltage (Vout) that indicates which input is greater.

  • Output States:

    • If V+ > V-, the output Vout goes to its positive saturation level, which is close to the positive supply voltage (VCC) of the op-amp.
    • If V+ < V-, the output Vout goes to its negative saturation level, which is close to the negative supply voltage (VEE) or ground (GND), if a single supply is used.
    • Ideally, if V+ = V-, the output should switch instantaneously. However, in practice, there is a small uncertainty region due to the comparator’s response time and noise.
  • Using Op-Amps as Comparators: Op-amps can be used as comparators, but specialized comparator ICs often provide better performance due to faster switching speeds and optimized input characteristics. Op-amps also need external components to stabilize the circuit.

  • Hysteresis: To prevent oscillations and false triggering due to noise, comparators often include hysteresis. Hysteresis introduces two different threshold voltages:

    • Upper Threshold (Vth+): The input voltage at which the output switches from low to high.
    • Lower Threshold (Vth-): The input voltage at which the output switches from high to low.
    • The difference between Vth+ and Vth- is the hysteresis voltage (ΔVth). This helps to create a stable switching behavior, preventing rapid toggling of the output when the input signal is near the threshold.
  • Open-Collector Output: Some comparators feature an open-collector output, which requires an external pull-up resistor. This allows for flexible interfacing with different voltage levels and logic families.

  • Applications: Comparators are used in numerous applications:

    • Zero-Crossing Detectors: Converting AC signals to digital signals.
    • Threshold Detectors: Monitoring voltage levels and triggering actions when a threshold is reached.
    • Analog-to-Digital Converters (ADCs): As a basic building block in certain ADC architectures.
    • Oscillators and Waveform Generators: In relaxation oscillators and other circuits.
  • Practical Considerations:

    • Response Time: The time it takes for the output to switch states after the input crosses the threshold. Faster response times are crucial for high-frequency applications.
    • Input Bias Current: The small current that flows into the input terminals of the comparator.
    • Input Offset Voltage: The small voltage difference between the inputs required to make the output switch states.
    • Noise Sensitivity: Comparators can be sensitive to noise, which can cause false triggering. Hysteresis and proper filtering can mitigate this.

Here is a summary in a table:

Feature Description
Input Voltages V+ (non-inverting) and V- (inverting)
Output States Vout goes high if V+ > V-, Vout goes low if V+ < V-
Op-Amps as Comparators Op-amps can be used but specialized comparator ICs offer better performance
Hysteresis Prevents oscillations by introducing upper (Vth+) and lower (Vth-) threshold voltages
Open-Collector Output Requires an external pull-up resistor for flexible interfacing
Applications Zero-crossing detectors, threshold detectors, ADCs, oscillators
Practical Considerations Response time, input bias current, input offset voltage, noise sensitivity

Electronic comparators are essential in numerous electronic applications, offering precise voltage comparisons that drive decision-making processes in circuits and systems. Understanding their operation and characteristics is crucial for effective design and implementation.

3. How Does a Comparator Work in Programming?

In programming, a comparator is a function or object that defines a comparison method used to determine the order of two elements. It’s particularly useful in sorting algorithms, data structures like priority queues, and search algorithms. Instead of directly containing elements, a comparator provides the logic to compare them.

  • Basic Functionality: A comparator takes two arguments (a and b) and returns a value indicating their relative order:

    • Returns a negative value if a < b
    • Returns zero if a == b
    • Returns a positive value if a > b
  • Implementation in Different Languages:

    • Java: Comparators are interfaces (java.util.Comparator) with a compare(Object a, Object b) method.
      
      import java.util.Comparator;

    public class CustomComparator implements Comparator {
    @Override
    public int compare(Integer a, Integer b) {
    return a – b; // Ascending order
    }
    }

    *   **Python**: Comparators are often implemented as lambda functions or custom functions used with the `sorted()` function or `sort()` method.
    ```python
    # Using a lambda function
    numbers = [3, 1, 4, 1, 5, 9, 2, 6]
    sorted_numbers = sorted(numbers, key=lambda x: x) # Ascending order
    
    # Using a custom function
    def custom_comparator(a, b):
        return a - b
    
    sorted_numbers = sorted(numbers, key=custom_comparator) # Ascending order
    • C++: Comparators can be function pointers, function objects (classes with an overloaded operator()), or lambda expressions.
      
      #include <algorithm>
      #include <vector>

    // Function object
    struct CustomComparator {
    bool operator()(int a, int b) {
    return a < b; // Ascending order
    }
    };

    int main() {
    std::vector numbers = {3, 1, 4, 1, 5, 9, 2, 6};
    std::sort(numbers.begin(), numbers.end(), CustomComparator());
    return 0;
    }

    *   **JavaScript**: Comparators are functions used with the `sort()` method of arrays.
    ```javascript
    let numbers = [3, 1, 4, 1, 5, 9, 2, 6];
    numbers.sort((a, b) => a - b); // Ascending order
  • Use Cases:

    • Sorting: Comparators are essential for sorting collections of objects based on specific criteria.
    • Priority Queues: They define the order in which elements are retrieved from a priority queue.
    • Searching: Comparators are used in binary search algorithms to find elements in a sorted collection.
  • Benefits:

    • Flexibility: Comparators allow you to define custom sorting logic without modifying the objects themselves.
    • Reusability: Comparators can be reused across multiple sorting operations with different criteria.
    • Abstraction: They abstract the comparison logic, making code more readable and maintainable.

Example:

Suppose you have a list of Student objects, and you want to sort them based on their GPA. Here’s how you can use a comparator in Java:

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;

class Student {
    String name;
    double gpa;

    public Student(String name, double gpa) {
        this.name = name;
        this.gpa = gpa;
    }

    public String getName() {
        return name;
    }

    public double getGpa() {
        return gpa;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", gpa=" + gpa +
                '}';
    }
}

class GpaComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return Double.compare(s2.getGpa(), s1.getGpa()); // Descending order
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 3.8));
        students.add(new Student("Bob", 3.6));
        students.add(new Student("Charlie", 3.9));

        System.out.println("Before sorting: " + students);

        Collections.sort(students, new GpaComparator());

        System.out.println("After sorting by GPA: " + students);
    }
}

In this example, GpaComparator implements the Comparator interface to compare Student objects based on their GPA. The compare method returns a value indicating the order of the students, allowing the Collections.sort method to sort the list accordingly.

Here is a summary in a table:

Feature Description
Basic Function Compares two elements and returns a negative, zero, or positive value to indicate their relative order
Implementation Varies by language (e.g., interfaces in Java, functions in Python)
Use Cases Sorting, priority queues, searching
Benefits Flexibility, reusability, abstraction

Comparators in programming are vital for defining custom comparison logic, enabling flexible and reusable sorting and searching operations. They enhance code readability and maintainability by abstracting the comparison process.

4. Does a Comparator Contain Elements?

No, a comparator does not contain elements. Its primary role is to define how two elements should be compared. It provides the logic for determining the order or equality of the elements but does not store or manage the elements themselves.

  • Separation of Concerns: Comparators adhere to the principle of separation of concerns. They focus solely on the comparison logic, leaving the management of elements to other data structures or algorithms.

  • Stateless Nature: Comparators are typically stateless, meaning they do not maintain any internal state related to the elements being compared. Each comparison is independent and based only on the input arguments.

  • Functional Interface: In many languages, comparators are implemented as functional interfaces or function objects, emphasizing their role as a function that performs a specific task (i.e., comparison).

Example:

Consider a scenario where you have a list of Product objects, and you want to sort them based on their price. The comparator would define how to compare the prices of two Product objects but would not store the Product objects themselves.

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;

class Product {
    String name;
    double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + ''' +
                ", price=" + price +
                '}';
    }
}

class PriceComparator implements Comparator<Product> {
    @Override
    public int compare(Product p1, Product p2) {
        return Double.compare(p1.getPrice(), p2.getPrice()); // Ascending order
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Product> products = new ArrayList<>();
        products.add(new Product("Laptop", 1200.0));
        products.add(new Product("Keyboard", 75.0));
        products.add(new Product("Mouse", 25.0));

        System.out.println("Before sorting: " + products);

        Collections.sort(products, new PriceComparator());

        System.out.println("After sorting by price: " + products);
    }
}

In this example, PriceComparator defines how to compare the prices of two Product objects. The ArrayList named products contains the actual Product objects. The comparator does not contain these products; it only provides the logic to compare their prices.

Here is a summary in a table:

Aspect Description
Role Defines how two elements should be compared
Containment Does not contain or store elements
Separation of Concerns Focuses solely on comparison logic, leaving element management to other data structures
Stateless Typically stateless; each comparison is independent
Functional Interface Implemented as functional interfaces or function objects in many languages

Comparators are designed to compare elements, not contain them. They operate as separate entities that provide comparison logic, ensuring that the management of elements remains with the appropriate data structures or algorithms.

5. When is a Comparator Used?

A comparator is used in various scenarios where you need to define a custom comparison logic between objects or values. Here are some common use cases:

  • Sorting:
    • Custom Sorting Criteria: When you need to sort a collection of objects based on a specific attribute or combination of attributes that is not the natural ordering. For instance, sorting a list of Employee objects by their salary, name, or hire date.
    • Non-Comparable Objects: When the objects you want to sort do not implement the Comparable interface or when you want to override the default comparison behavior.
    • Dynamic Sorting: When the sorting criteria need to be determined at runtime. You can select a comparator based on user input or configuration settings.

Example:

Suppose you have a list of Book objects, and you want to sort them based on their title, author, or publication date. You can use comparators to define different sorting strategies:

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;

class Book {
    String title;
    String author;
    Date publicationDate;

    public Book(String title, String author, Date publicationDate) {
        this.title = title;
        this.author = author;
        this.publicationDate = publicationDate;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public Date getPublicationDate() {
        return publicationDate;
    }

    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + ''' +
                ", author='" + author + ''' +
                ", publicationDate=" + publicationDate +
                '}';
    }
}

class TitleComparator implements Comparator<Book> {
    @Override
    public int compare(Book b1, Book b2) {
        return b1.getTitle().compareTo(b2.getTitle()); // Ascending order by title
    }
}

class AuthorComparator implements Comparator<Book> {
    @Override
    public int compare(Book b1, Book b2) {
        return b1.getAuthor().compareTo(b2.getAuthor()); // Ascending order by author
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Book> books = new ArrayList<>();
        books.add(new Book("The Great Gatsby", "F. Scott Fitzgerald", new Date(1925, 4, 10)));
        books.add(new Book("To Kill a Mockingbird", "Harper Lee", new Date(1960, 6, 11)));
        books.add(new Book("1984", "George Orwell", new Date(1949, 5, 8)));

        System.out.println("Before sorting: " + books);

        Collections.sort(books, new TitleComparator());
        System.out.println("After sorting by title: " + books);

        Collections.sort(books, new AuthorComparator());
        System.out.println("After sorting by author: " + books);
    }
}
  • Priority Queues:
    • Custom Priority: When you need to implement a priority queue with a custom priority definition. For example, processing tasks based on their urgency or importance.

Example:

Suppose you have a list of Task objects, and you want to process them based on their priority. You can use a comparator to define the priority order:

import java.util.Comparator;
import java.util.PriorityQueue;

class Task {
    String name;
    int priority;

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    public String getName() {
        return name;
    }

    public int getPriority() {
        return priority;
    }

    @Override
    public String toString() {
        return "Task{" +
                "name='" + name + ''' +
                ", priority=" + priority +
                '}';
    }
}

class PriorityComparator implements Comparator<Task> {
    @Override
    public int compare(Task t1, Task t2) {
        return t1.getPriority() - t2.getPriority(); // Ascending order by priority
    }
}

public class Main {
    public static void main(String[] args) {
        PriorityQueue<Task> taskQueue = new PriorityQueue<>(new PriorityComparator());
        taskQueue.add(new Task("Backup Database", 3));
        taskQueue.add(new Task("Fix Critical Bug", 1));
        taskQueue.add(new Task("Update Documentation", 5));

        System.out.println("Processing tasks in priority order:");
        while (!taskQueue.isEmpty()) {
            Task task = taskQueue.poll();
            System.out.println("Processing: " + task);
        }
    }
}
  • Searching:
    • Binary Search: When you need to perform a binary search on a collection of objects that are not naturally comparable.

Example:

Suppose you have a sorted list of Event objects, and you want to find an event by its start time. You can use a comparator to define how to compare event times:

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;

class Event {
    String name;
    Date startTime;

    public Event(String name, Date startTime) {
        this.name = name;
        this.startTime = startTime;
    }

    public String getName() {
        return name;
    }

    public Date getStartTime() {
        return startTime;
    }

    @Override
    public String toString() {
        return "Event{" +
                "name='" + name + ''' +
                ", startTime=" + startTime +
                '}';
    }
}

class EventTimeComparator implements Comparator<Event> {
    @Override
    public int compare(Event e1, Event e2) {
        return e1.getStartTime().compareTo(e2.getStartTime()); // Ascending order by start time
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Event> events = new ArrayList<>();
        events.add(new Event("Meeting", new Date(2024, 6, 1, 10, 0)));
        events.add(new Event("Conference", new Date(2024, 6, 2, 14, 0)));
        events.add(new Event("Workshop", new Date(2024, 6, 3, 9, 0)));

        Collections.sort(events, new EventTimeComparator()); // Ensure the list is sorted

        Date searchTime = new Date(2024, 6, 2, 14, 0);
        Event searchEvent = new Event("Conference", searchTime); // Dummy event for searching

        int index = Collections.binarySearch(events, searchEvent, new EventTimeComparator());

        if (index >= 0) {
            System.out.println("Found event: " + events.get(index));
        } else {
            System.out.println("Event not found.");
        }
    }
}
  • Data Structures:
    • Custom Implementations: When you are implementing your own data structures that require custom comparison logic, such as custom trees or graphs.

Example:

Suppose you are implementing a custom binary search tree that stores Contact objects, and you want to define the tree structure based on the contact’s name:

import java.util.Comparator;

class Contact {
    String name;
    String phone;

    public Contact(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "name='" + name + ''' +
                ", phone='" + phone + ''' +
                '}';
    }
}

class ContactNameComparator implements Comparator<Contact> {
    @Override
    public int compare(Contact c1, Contact c2) {
        return c1.getName().compareTo(c2.getName()); // Ascending order by name
    }
}

class BinarySearchTree {
    static class Node {
        Contact data;
        Node left;
        Node right;

        Node(Contact data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }

    private Node root;
    private Comparator<Contact> comparator;

    public BinarySearchTree(Comparator<Contact> comparator) {
        this.root = null;
        this.comparator = comparator;
    }

    public void insert(Contact data) {
        root = insertRecursive(root, data);
    }

    private Node insertRecursive(Node root, Contact data) {
        if (root == null) {
            return new Node(data);
        }

        int compareResult = comparator.compare(data, root.data);

        if (compareResult < 0) {
            root.left = insertRecursive(root.left, data);
        } else if (compareResult > 0) {
            root.right = insertRecursive(root.right, data);
        } else {
            // Duplicate data, handle as needed
        }

        return root;
    }

    public void inorderTraversal() {
        inorderTraversalRecursive(root);
    }

    private void inorderTraversalRecursive(Node root) {
        if (root != null) {
            inorderTraversalRecursive(root.left);
            System.out.println(root.data);
            inorderTraversalRecursive(root.right);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ContactNameComparator contactNameComparator = new ContactNameComparator();
        BinarySearchTree bst = new BinarySearchTree(contactNameComparator);

        bst.insert(new Contact("Alice", "123-456-7890"));
        bst.insert(new Contact("Bob", "987-654-3210"));
        bst.insert(new Contact("Charlie", "456-789-0123"));

        System.out.println("Inorder traversal of the binary search tree:");
        bst.inorderTraversal();
    }
}
  • Generic Algorithms:
    • Extending Functionality: When you want to use generic algorithms that require a comparison function, such as the sort function in C++ or the sorted function in Python.

Here is a summary in a table:

Use Case Description
Sorting Sorting collections based on custom criteria, non-comparable objects, or dynamic sorting requirements.
Priority Queues Implementing priority queues with custom priority definitions.
Searching Performing binary search on collections that are not naturally comparable.
Data Structures Implementing custom data structures (e.g., trees, graphs) that require custom comparison logic.
Generic Algorithms Using generic algorithms that require a comparison function (e.g., sort in C++, sorted in Python).

Comparators are versatile tools for defining custom comparison logic in a wide range of programming scenarios. They enable flexible sorting, priority management, searching, and data structure implementations.

6. Benefits of Using a Comparator

Using a comparator offers several benefits in programming, making it a powerful tool for customizing comparison logic. Here are some key advantages:

  • Custom Sorting:
    • Flexibility: Comparators allow you to define custom sorting criteria based on specific attributes or combinations of attributes. This flexibility is essential when the natural ordering of objects is not sufficient.
    • Complex Criteria: You can implement complex comparison logic that involves multiple fields, conditional statements, and custom calculations.

Example:

Suppose you have a list of Product objects, and you want to sort them based on a combination of their price and rating. Products with higher ratings should come first, and among products with the same rating, the cheaper ones should come first:

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;

class Product {
    String name;
    double price;
    int rating;

    public Product(String name, double price, int rating) {
        this.name = name;
        this.price = price;
        this.rating = rating;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public int getRating() {
        return rating;
    }

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + ''' +
                ", price=" + price +
                ", rating=" + rating +
                '}';
    }
}

class ProductComparator implements Comparator<Product> {
    @Override
    public int compare(Product p1, Product p2) {
        // First, compare by rating (descending order)
        int ratingComparison = Integer.compare(p2.getRating(), p1.getRating());
        if (ratingComparison != 0) {
            return ratingComparison; // If ratings are different, return the rating comparison
        } else {
            // If ratings are the same, compare by price (ascending order)
            return Double.compare(p1.getPrice(), p2.getPrice());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Product> products = new ArrayList<>();
        products.add(new Product("Laptop", 1200.0, 4));
        products.add(new Product("Keyboard", 75.0, 5));
        products.add(new Product("Mouse", 25.0, 5));
        products.add(new Product("Monitor", 300.0, 4));

        System.out.println("Before sorting: " + products);

        Collections.sort(products, new ProductComparator());

        System.out.println("After sorting by rating and price: " + products);
    }
}
  • Decoupling:
    • Separation of Concerns: Comparators separate the comparison logic from the object’s definition, adhering to the principle of separation of concerns.
    • Maintainability: This decoupling makes the code more maintainable because changes to the comparison logic do not require modifications to the object’s class.
    • Reusability: Comparators can be reused across multiple sorting operations with different criteria, reducing code duplication.

Example:

Suppose you have a Student class, and you want to sort students based on their GPA or their name. You can define separate comparators for each criterion without modifying the Student class:

import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;

class Student {
    String name;
    double gpa;

    public Student(String name, double gpa) {
        this.name = name;
        this.gpa = gpa;
    }

    public String getName() {
        return name;
    }

    public double getGpa() {
        return gpa;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", gpa=" + gpa +
                '}';
    }
}

class GpaComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return Double.compare(s2.getGpa(), s1.getGpa()); // Descending order by GPA
    }
}

class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.getName().compareTo(s2.getName()); // Ascending order by name
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 3.8));
        students.add(new Student("Bob", 3.6));
        students.add(new Student("Charlie", 3.9));

        System.out.println("Before sorting: " + students);

        Collections.sort(students, new GpaComparator());
        System.out.println("After sorting by GPA: " + students);

        Collections.sort(students, new NameComparator());
        System.out.println("After sorting by name: " + students);
    }
}
  • Dynamic Sorting:
    • Runtime Flexibility: Comparators allow you to determine the sorting criteria at runtime. You can select a comparator based on user input, configuration settings, or other dynamic factors.

Example:

Suppose you have a program that allows users to sort a list of products by different criteria (e.g., price, rating, name). You can use a comparator to implement dynamic sorting based on the user’s selection:


import java.util.Comparator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

class Product {
    String name;
    double price;
    int rating;

    public Product(String name, double price, int rating) {
        this.name = name;
        this.price = price;
        this.rating = rating;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public int getRating() {
        return rating;
    }

    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + ''' +
                ", price=" + price +
                ", rating=" + rating +
                '}';
    }
}

class PriceComparator implements Comparator<Product> {
    @Override
    public int compare(Product p1, Product p2) {
        return Double.compare(p1.getPrice(), p2.getPrice()); // Ascending order by price
    }
}

class RatingComparator implements Comparator<Product> {
    @Override
    public int compare(Product p1, Product p2) {
        return Integer.compare(p2.getRating(), p1.getRating()); // Descending order by rating
    }
}

class NameComparator implements Comparator<Product> {
    @Override
    public int compare(Product p1, Product p2) {
        return p1.getName().compareTo(p2.getName()); // Ascending order by name
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Product> products = new ArrayList<>();
        products.add(new Product("Laptop", 1200.0, 4));
        products.add(new Product("Keyboard", 75.0, 5));
        products.add(new Product("Mouse", 25.0, 5));
        products.add(new Product("Monitor", 300.0, 4));

        Scanner scanner = new Scanner(System.in);
        System.out.println("Sort by: (1) Price, (2) Rating, (3) Name");
        int choice = scanner.nextInt();

        Comparator<Product> comparator;
        switch (choice) {
            case 1:
                comparator = new PriceComparator();
                break;
            case 2:
                comparator = new RatingComparator();
                break;
            case 3:
                comparator = new Name

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *