I am a newbie of c++.
Now I am doing a project need to read a customer list from a csv file and then search if there is a username like "Ali" and printout all the data about Ali.
How can I search "Ali" and printout all the data about Ali like CustomerNo , Name , PhoneNo and Status?
And if there is multiple data with "Ali" , how can I printout all of them either?
Here is my code:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Iterator;
public class LoadCustomer {
public static void main(String[] args) throws IOException{
System.out.println ("Load customer from file");
ArrayList<Customer> customers = readCustomerFromFile();
System.out.println (customers);
System.out.println ();
private static ArrayList<Customer> readCustomerFromFile() throws IOException{
ArrayList<Customer> customers = new ArrayList<>();
List<String> lines = Files.readAllLines(Paths.get("customer.csv"));
for (int i = 1 ; i < lines.size() ; i++){
String[] items = lines.get(i).split(",");
int customerNo = Integer.parseInt(items[0]);
int phoneNo = Integer.parseInt(items[2]);
customers.add (new Customer(customerNo,items[1],phoneNo,items[3]));
}
return customers;
}
}
Here is my Customer class:(added getName getter)
public class Customer {
private int customerNo;
private String name;
private int phoneNo;
private String status;
public Customer () {}
public Customer (int customerNo, String name, int phoneNo, String status){
this.customerNo = customerNo;
this.name = name;
this.phoneNo = phoneNo;
this.status = status;
}
public String getName(){
return name;
}
public String toString(){
return customerNo + " " + name + " " + phoneNo + " " + status;
}
public String toCSVString(){
return customerNo + "," + name + "," + phoneNo + "," + status;
}
}
And here is my data:
CustomerNo Name PhoneNo Status
1 Ali 12345 Normal
2 Siti 23456 Normal
3 Rone 78910 Normal
4 Jean 56789 Normal
5 Roby 28573 Normal
6 Ali 78532 Normal
Thank you very much for your attention.
Edited :
Here is my code for this program:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class FindCustomer {
public static void main(String[] args) throws IOException{
System.out.println ("Load customer from file");
java.util.Map<String, List<Customer>> customers =
Files.lines(Paths.get("customer.csv"))
.map(line -> line.split(","))
.map(field -> new Customer(
Integer.parseInt(field[0]), field[1],
Integer.parseInt(field[2]), field[3]))
.collect(Collectors
.groupingBy(Customer::getName));
System.out.println (customers);
}
}
Bit of a broad question.
If you expect to do this a lot, and on a boatload of data, do what everybody else does when they are faced with a lot of relational data that they need to run queries on. Use a database, like postgres or h2. To interact with those from java, use JDBI or JOOQ.
If this is just a small simple text file and/or you're trying to learn some java, well, you still have two options here: You can loop through the data, or, you can build a mapping.
The loop option is simple:
for (Customer c : customers) if (c.getName().equals("Ali")) {
// do what you want here. 'c' holds the customer object of Ali.
}
But this does, of course, require a full run through all the entries every time. Another option is to build a mapping:
var map = new HashMap<String, Customer>();
for (Customer c : customers) map.put(c.getName(), c);
// map now maps a customer name to the customer object.
Customer ali = map.get("Ali");
maps have the advantage that they are near instant lookup. Even if the map contains a million entries, map.get(x) is (near) instant. A decent solution if you have lots of data + the need to do lots of lookups. But, you have to build a complete map for everything you care to query on. So, if you want to do lookups on name, and then later something like 'get all customers with a 6 digit phone number whose status is Normal', then, get a database.
As was suggested a map would be useful. You can create one on the fly as you read in the file.
Splits the line
creates a customer.
and groups it by name in a map.
Now the map will hold for each name, all customers that have that name.
Map<String, List<Customer>> customers =
Files.lines(Paths.get("customer.csv"))
.map(line -> line.split("\\s*,\\s*"))
.map(field -> new Customer(
Integer.parseInt(field[0]), field[1],
Integer.parseInt(field[2]), field[3]))
.collect(Collectors
.groupingBy(Customer::getName));
To get the List of customers for the name Ali do the following.
List<Customer> ali = customers.get("Ali");
Now it's up to you to format or otherwise use the list as required. You will still need to handle exceptions via try/catch.
Related
Here is my code:
public static Map<String, List<Customer>> readCustomerData() throws IOException {
Map<String, List<Customer>> customers =
Files.lines(Paths.get("customer.csv"))
.map(line -> line.split("\\s*,\\s*"))
.map(field -> new Customer(
Integer.parseInt(field[0]), field[1],
Integer.parseInt(field[2]), field[3]))
.collect(Collectors
.groupingBy(Customer::getName));
System.out.println (customers);
return customers;
}
I notice that this code read my data in the csv file into one element like this:
(Ali = ["1 Ali 1201345673 Normal"] , Siti = ["2 Siti 1307891435 Normal"])
But in my thinking , I would like to read the data like the array list such as for Ali: 1 is an element , Ali is an element , 1201345673 is an element and Normal is another element in the list in the Map customer. How can I modify my code to do such a thing?
This is my Customer class just in case:
public class Customer {
private int customerNo;
private String name;
private int phoneNo;
private String status;
public Customer () {}
public Customer (int customerNo, String name, int phoneNo, String status){
this.customerNo = customerNo;
this.name = name;
this.phoneNo = phoneNo;
this.status = status;
}
public String getName(){
return name;
}
public String toString(){
return customerNo + " " + name + " " + phoneNo + " " + status;
}
Here is my csv file:
1,Ali,1201345673,Normal
2,Siti,1307891435,Normal
Thank you for your attention.
Assuming that the customer names are unique, there's no need to return a Map<String, List<Customer>>, since each List will contain a single Customer.
You can change your code to:
Map<String, Customer> customers =
Files.lines(Paths.get("customer.csv"))
.map(line -> line.split("\\s*,\\s*"))
.map(field -> new Customer(
Integer.parseInt(field[0]), field[1],
Integer.parseInt(field[2]), field[3]))
.collect(Collectors.toMap(Customer::getName, Function.identity()));
And if the names are not unique, you can index the customers by the customer IDs.
As for I would like to read the data like the array list such as for Ali: 1 is an element , Ali is an element , 1201345673 is an element and Normal is another element in the list in the Map customer - this doesn't make sense to me. You already create a Customer object from each line of your input, which is much more useful and type safe compared to a List of properties.
I am doing a coding exercise where I take the the raw data from a csv file and I print it in order of lowest to highest ranked literacy rates.
For example:
Adult literacy rate, population 15+ years, female (%),United Republic of Tanzania,2015,76.08978
Adult literacy rate, population 15+ years, female (%),Zimbabwe,2015,85.28513
Adult literacy rate, population 15+ years, male (%),Honduras,2014,87.39595
Adult literacy rate, population 15+ years, male (%),Honduras,2015,88.32135
Adult literacy rate, population 15+ years, male (%),Angola,2014,82.15105
Turns into:
Niger (2015), female, 11.01572
Mali (2015), female, 22.19578
Guinea (2015), female, 22.87104
Afghanistan (2015), female, 23.87385
Central African Republic (2015), female, 24.35549
My code:
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class LiteracyComparison {
public static void main(String[] args) throws IOException {
List<String> literacy = new ArrayList<>();
try (Scanner scanner = new Scanner(Paths.get("literacy.csv"))) {
while(scanner.hasNextLine()){
String row = scanner.nextLine();
String[] line = row.split(",");
line[2] = line[2].trim().substring(0, line[2].length() - 5);
line[3] = line[3].trim();
line[4] = line[4].trim();
line[5] = line[5].trim();
String l = line[3] + " (" + line[4] + "), " + line[2] + ", " + line[5];
literacy.add(l);
}
}
// right about where I get lost
literacy.stream().sorted();
}
}
Now I have converted the raw data into the correct format, it's just I am lost on how to sort it.
I am also wondering if there is a more efficient way to do this via the streams method. Please and thank you.
I took a few liberties while refactoring your code, but the idea is the same. This could be further improved but it is not intended to be a perfect solution, just something to answer your question and put you on the right track.
The main idea here is to create a nested class called LiteracyData, which stores the summary you had before as a String. However, we also want to store the literacy rate so we have something to sort by. Then you can use a Java Comparator to define your own method for comparing custom classes, in this case LiteracyData. Finally, tie it all together by calling the sort function on your List, while passing in the custom Comparator as an argument. That will sort your list. You can then print it to view the results.
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Comparator;
public class LiteracyComparison {
// Define a class that stores your data
public class LiteracyData {
private String summary;
private float rate;
public LiteracyData(String summary, float rate) {
super();
this.summary = summary;
this.rate = rate;
}
}
// This is a custom Comparator we defined for sorting LiteracyData
public class LiteracySorter implements Comparator<LiteracyData>
{
#Override
public int compare(LiteracyData d1, LiteracyData d2) {
return Float.compare(d1.rate, d2.rate);
}
}
public void run() {
List<LiteracyData> literacy = new ArrayList<>();
try (Scanner scanner = new Scanner(Paths.get("literacy.csv"))) {
while(scanner.hasNextLine()){
String row = scanner.nextLine();
String[] line = row.split(",");
line[2] = line[2].trim().substring(0, line[2].length() - 5);
line[3] = line[3].trim();
line[4] = line[4].trim();
line[5] = line[5].trim();
String l = line[3] + " (" + line[4] + "), " + line[2] + ", " + line[5];
LiteracyData data = new LiteracyData(l, Float.parseFloat(line[5]));
literacy.add(data);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
// Sort the list using your custom LiteracyData comparator
literacy.sort(new LiteracySorter());
// Iterate through the list and print each item to ensure it is sorted
for(LiteracyData data : literacy) {
System.out.println(data.summary);
}
}
public static void main(String[] args) throws IOException {
LiteracyComparison comparison = new LiteracyComparison();
comparison.run();
}
}
I am pretty new into programming and I have an assignment to make, but I got stuck.
I have to implement a program which will read a CSV file (1 million+ lines) and count how many clients ordered "x" distinct products on a specific day.
The CSV looks like this:
Product Name | Product ID | Client ID | Date
Name 544 86 10/12/2017
Name 545 86 10/12/2017
Name 644 87 10/12/2017
Name 644 87 10/12/2017
Name 9857 801 10/12/2017
Name 3022 801 10/12/2017
Name 3021 801 10/12/2017
The result from my code is:
801: 2 - incorrect
86: 2 - correct
87: 2 - incorrect
Desired output is:
Client 1 (801): 3 distinct products
Client 2 (86): 2 distinct products
Client 3 (87): 1 distinct product
Additionally,
If I want to know how many clients ordered 2 distinct products I would like a result to look like this:
Total: 1 client ordered 2 distinct products
If I want to know the maximum number of distinct products ordered in a day, I would like the result to look like this:
The maximum number of distinct products ordered is: 3
I tried to use a Hash Map and Multimap by Google Guava (my best guess here), but I couldn't wrap my head around it.
My code looks like this:
package Test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
public class Test {
public static void main(String[] args) {
//HashMultimap<String, String> myMultimap = HashMultimap.create();
Map<String, MutableInteger> map = new HashMap<String, MutableInteger>();
ArrayList<String> linesList = new ArrayList<>();
// Input of file which needs to be parsed
String csvFile = "file.csv";
BufferedReader csvReader;
// Data split by 'TAB' in CSV file
String csvSplitBy = "\t";
try {
// Read the CSV file into an ArrayList array for easy processing.
String line;
csvReader = new BufferedReader(new FileReader(csvFile));
while ((line = csvReader.readLine()) !=null) {
linesList.add(line);
}
csvReader.close();
} catch (IOException e) {
e.printStackTrace();
}
// Process each CSV file line which is now contained within
// the linesList list Array
for (int i = 0; i < linesList.size(); i++) {
String[] data = linesList.get(i).split(csvSplitBy);
String col2 = data[1];
String col3 = data[2];
String col4 = data[3];
// Determine if Column 4 has the desired date
// and count the values
if (col4.contains("10/12/2017")) {
String key = col3;
if (map.containsKey(key)) {
MutableInteger count = map.get(key);
count.set(count.get() + 1);
} else {
map.put(key, new MutableInteger(1));
}
}
}
for (final String k : map.keySet()) {
if (map.get(k).get() == 2) {
System.out.println(k + ": " + map.get(k).get());
}
}
}
}
Any advise or suggestion on how this can be implemented would be greatly appreciated.
Thank you in advance guys.
You could store a Setof productIds per clientId, and just take the size of that.
As a Set does not allow duplicate values, this will effectively give you the distinct number of productIds.
Also, I recommend that you give your variables meaningful name instead of col2, k, map... This will make your code more readable.
Map<String, Set<String>> distinctProductsPerClient = new HashMap<String, Set<String>>();
// Process each CSV file line which is now contained within
// the linesList list Array
// Start from 1 to skip the first line
for (int i = 1; i < linesList.size(); i++) {
String line = linesList.get(i);
String[] data = line.split(csvSplitBy);
String productId = data[1];
String clientId = data[2];
String date = data[3];
// Determine if Column 4 has the desired date
// and count the values
if (date.contains("10/12/2017")) {
if (!distinctProductsPerClient.containsKey(clientId)) {
distinctProductsPerClient.put(clientId, new HashSet<>());
}
distinctProductsPerClient.get(clientId).add(productId);
}
}
for (final String clientId : distinctProductsPerClient.keySet()) {
System.out.println(clientId + ": " + distinctProductsPerClient.get(clientId).size());
}
More advanced solution using Stream API (requires Java 9)
If you introduce the class OrderData(that represents a single line in the CSV) like this:
private static class OrderData {
private final String productName;
private final String productId;
private final String clientId;
private final String date;
public OrderData(String csvLine) {
String[] data = csvLine.split("\t");
this.productName = data[0];
this.productId = data[1];
this.clientId = data[2];
this.date = data[3];
}
public String getProductName() {
return productName;
}
public String getProductId() {
return productId;
}
public String getClientId() {
return clientId;
}
public String getDate() {
return date;
}
}
you can replace the for loop with this:
Map<String, Set<String>> distinctProductsPerClient2 = linesList.stream()
.skip(1)
.map(OrderData::new)
.collect(groupingBy(OrderData::getClientId, mapping(OrderData::getProductId, toSet())));
But I reckon this might be a little bit to complex if you're new into programming (although it might be a good exercise if you would try to understand what the above code does).
I'm trying to get a CSV from some data retrieved by Oracle. I have just to write the csv, using the result of the query as column of csv. This is my code:
// get data
final List<myDto> dataCsv = myDao.getdata();
StringWriter writer = new StringWriter();
CSVWriter csvWriter = new CSVWriter(writer,';');
List<String[]> result = toStringArray(dataCsv);
csvWriter.writeAll(result);
csvWriter.close();
return Response.ok(result).header("Content-Disposition", "attachment; filename=" + fileName).build();`
Obviously it can't find toStringArray(). But have I to build it? Do I really need it? How do I have to edit the edit to get it working?
If you just follow the example from the link that you've given, you'll see what they're doing...
private static List<String[]> toStringArray(List<Employee> emps) {
List<String[]> records = new ArrayList<String[]>();
//add header record
records.add(new String[]{"ID","Name","Role","Salary"});
Iterator<Employee> it = emps.iterator();
while(it.hasNext()){
Employee emp = it.next();
records.add(new String[]{emp.getId(),emp.getName(),emp.getRole(),emp.getSalary()});
}
return records;
}
Essentially, you need to build a List of String[]. Each String[] represents a single line of data for the CSV, with each element of the array being a value. So, yes, you need to build a List from your data model and pass it to the CSVWriter's writeAll() method.
The first String[] in the list is the column headers for the CSV. The subsequent String arrays are the data itself.
Apache Commons CSV
The Apache Commons CSV library can help with the chore of reading/writing CSV files. It handles several variants of the CSV format, including the one used by Oracle.
• CSVFormat.ORACLE
Employee.java
Let's make a class for Employee.
package work.basil.example;
import java.util.Objects;
public class Employee {
public Integer id;
public String name, role;
public Integer salary;
public Employee ( Integer id , String name , String role , Integer salary ) {
Objects.requireNonNull( id ); // etc.
this.id = id;
this.name = name;
this.role = role;
this.salary = salary;
}
#Override
public String toString ( ) {
return "Employee{ " +
"id=" + id +
" | name='" + name + '\'' +
" | role='" + role + '\'' +
" | salary=" + salary +
" }";
}
}
Example app
Make another class to mimic retrieving your DTOs. Then we write to a CSV file.
Obviously it can't find toStringArray(). But have I to build it? Do I really need it? How do I have to edit the edit to get it working?
To answer your specific Question, there is no toStringArray method to create field values for the CSV from your DTO object‘s member variables.
Binding
This idea of mapping input or output data with member variables of a Java object is generally known as binding.
There are sophisticated binding libraries for Java to bind your objects with XML and with JSON, JAXB and JSON-B respectively. Objects can be automatically written out to XML or JSON text, as well as “re-hydrated” back to objects when read from such XML or JSON text.
But for CSV with a simpler library such as Apache Commons CSV, we read and write each field of data individually for each object. You pass each DTO object member variable, and Commons CSV will write those values out to the CSV text with any needed encapsulating quote marks, commas, and escaping.
You can see this in the code below, in this line:
printer.printRecord( e.id , e.name , e.role , e.salary );
EmployeeIo.java
Here is the entire EmployeeIo.java file where Io means input-output.
package work.basil.example;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class EmployeeIo {
public static void main ( String[] args ) {
EmployeeIo app = new EmployeeIo();
app.doIt();
}
private void doIt ( ) {
// Mimic a collection of DTO objects coming from the database.
List < Employee > employees = new ArrayList <>( 3 );
employees.add( new Employee( 101 , "Alice" , "Boss" , 11_000 ) );
employees.add( new Employee( 102 , "Bob" , "Worker" , 12_000 ) );
employees.add( new Employee( 103 , "Carol" , "Worker" , 13_000 ) );
Path path = Paths.get( "/Users/basilbourque/Employees.csv" );
this.write( employees , path );
}
public void write ( final List < Employee > employees , final Path path ) {
try ( final CSVPrinter printer = CSVFormat.ORACLE.withHeader( "Id" , "Name" , "Role" , "Salary" ).print( path , StandardCharsets.UTF_8 ) ; ) {
for ( Employee e : employees ) {
printer.printRecord( e.id , e.name , e.role , e.salary );
}
} catch ( IOException e ) {
e.printStackTrace();
}
}
}
When run, we produce a file.
Hi i have a text file(tab seperated).
I would like to open it, read it and filter the required columns just like we do in excel. Could someone help with a sample code.
I am stuck up with the concept on how to proceed further for the below steps.
Price has to sorted with DESC order before processing.
Always, First two column has to be printed in the output.
Other than the first two columns only the required column has to be printed based on the input given.
Input will be something like (Mango/purchased/top50). so it should pick only top50 "yet to buy" under "Mango" along with its respective first two columns.
Sample input file.
itemNumber Price Mango Apple Bannana
112201 purchased need to plan purchased
112202 55 yet to buy yet to buy purchased
112202 67 need to plan purchased purchased
112203 456 need to plan need to plan need to plan
112203 33 need to plan yet to buy need to plan
112204 456 need to plan yet to buy need to plan
112204 yet to buy purchased need to plan
112205 77 yet to buy purchased need to plan
112205 99 yet to buy purchased yet to buy
112206 0 yet to buy purchased yet to buy
The code is incomplete.
Here i am trying to add the heading of the file to an arraylist and adding the content to an another arraylist. Then trying to compare them using index number. Is this way correct ?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class main {
#SuppressWarnings({ "resource", "unused" })
public static void main(String[] args) throws IOException {
ZipFile zipFile = new ZipFile(
"filename.tsv.zip");
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
String fruit = "Mango";
String mappingstatus = "purchased";
// reading a file
ZipEntry entry = entries.nextElement();
InputStream stream = zipFile.getInputStream(entry);
InputStreamReader read = new InputStreamReader(stream);
BufferedReader br = new BufferedReader(read);
// creating a new list
List<String> heading = new ArrayList<String>();
String[] a = br.readLine().split("\t");
heading = Arrays.asList(a);
List<String> content = new ArrayList<String>();
String s;
while ((s = br.readLine()) != null) {
String[] b = br.readLine().split("\t");
content = Arrays.asList(b);
}
}
}
}
Try this
class Item implements Comparable<Item> {
int itemNumber;
int price;
String mango;
String apple;
String bannana;
public Item(int itemNumber, int price, String mango, String apple, String bannana) {
this.itemNumber = itemNumber;
this.price = price;
this.mango = mango;
this.apple = apple;
this.bannana = bannana;
}
//GETTERS
#Override
public int compareTo(Item compareItem) {
int comparePrice = ((Item) compareItem).getPrice();
//ascending order
//return this.price - comparePrice;
//descending order
return comparePrice - this.price;
}
}
public static void main(String[] args) {
List<Item> items = new ArrayList<>();
//populate the items list by creating an Item for every line you read.
//Handle null price values
Collections.sort(items);
//assuming input is some like 'Mango/purchased/top50'
String input = "Mango/purchased/top50";
String[] parts = input.split("/");
int max = Integer.parseInt(parts[2].substring(3));
List<Item> result = new ArrayList<>();
for (int i = 0; i < items.size() && result.size() < max; i++) {
Item item = items.get(i);
if ((parts[0].equals("Mango") && item.getMango().equals(parts[1]))
|| (parts[0].equals("Apple") && item.getApple().equals(parts[1]))
|| (parts[0].equals("Bannana") && item.getBannana().equals(parts[1]))) {
result.add(item);
}
}
}
Complete the commented sections and it must work. More references about sorting here: Sorting