HashMap Practice - Customers Dataset
Context (why this matters)
HashMaps are one of the most useful structures in programming because they allow fast lookups, grouping, counting, and building indexes from real data.
In real projects (and interviews), it's common to load a dataset (like customers) and then build maps such as "ID → Customer", "City → List of Customers", or "Domain → Customers".
Given code (already provided)
The following classes are already implemented and must not be rewritten:
Customer- Represents one customer with fields like
id,name,email,age, andcity. -
Implements
Comparablewith a natural order based on customerid(ascending). -
CustomerFileReader - Reads customer data from a text/CSV file and returns a list of customers.
- The file has a header line like:
CustomerID,Name,Email,Age,City.
Input file
You will work with a file called customers.txt
CustomerID,Name,Email,Age,City
1,Alan Turing,alan.turing@bletchley.uk,41,London
2,Ada Lovelace,ada.lovelace@analytical.engine,36,London
3,Grace Hopper,grace.hopper@navy.mil,85,New York
...
Your tasks
Create a new class:
CustomerCollectionsDemo
This class will contain methods that practice HashMaps. Then create a main class to read from customers.txt and demonstrate that each method works.
Task 1 - Index customers by ID
Method: indexById(List<Customer> customers)
Return: Map<Integer, Customer>
Goal: Build a map where the key is customerId and the value is the Customer object.
Example idea: map.get(1912) should return the customer with ID 1912.
Task 2 - Count customers per city
Method: countByCity(List<Customer> customers)
Return: Map<String, Integer>
Goal: Create a map like: - "London" -> 12 - "Paris" -> 6
Task 3 - Group customers by city (key → list)
Method: groupByCity(List<Customer> customers)
Return: Map<String, List<Customer>>
Goal: Store a city as a key, and as value store all customers from that city in a list.
Task 4 - Find all customers from a specific city
Method: getCustomersFromCity(Map<String, List<Customer>> byCity, String city)
Return: List<Customer>
Goal: Using the grouped map from Task 3, return the list for one city.
If the city does not exist in the map, return an empty list.
Task 5 - Nested grouping: city → age → customers
Method: groupByCityThenAge(List<Customer> customers)
Return: Map<String, Map<Integer, List<Customer>>>
Goal: Create a nested structure such as: - "London" -> { 36 -> [Ada Lovelace] } - "Stanford" -> { 87 -> [Donald Knuth], 84 -> [John McCarthy] }
This is a very common "real data" pattern: grouping by multiple attributes.
Task 6 - Group customers by email domain
Method: groupByEmailDomain(List<Customer> customers)
Return: Map<String, List<Customer>>
Goal: Extract the domain from emails (everything after @) and group customers: - "gmail.com" -> [customers...] - "yahoo.com" -> [customers...]
If an email is malformed (no @), skip that customer.
Task 7 - Sort customers using Comparable
Method: sortCustomersNatural(List<Customer> customers)
Return: List<Customer>
Goal: Return a new list sorted using the natural ordering from Customer.compareTo, which is based on customer id.
Main program requirements
Create a Main class with a main method that:
- Reads customers from
customers.txtusingCustomerFileReader. - Calls each task method (1–7).
- Prints results clearly (examples: print the map size, print one group, print sorted list).
Remember: Programs must be written for people to read, and only incidentally for machines to execute.