I am working on a project where I have been given a text file and I have to add up the points for each team and printout the top 5 teams.
The text file looks like this:
FRAMae Berenice MEITE 455.455<br>
CHNKexin ZHANG 454.584<br>
UKRNatalia POPOVA 453.443<br>
GERNathalie WEINZIERL 452.162<br>
RUSEvgeny PLYUSHCHENKO 191.399<br>
CANPatrick CHAN 189.718<br>
CHNHan YAN 185.527<br>
CHNCheng & Hao 271.018<br>
ITAStefania & Ondrej 270.317<br>
USAMarissa & Simon 264.256<br>
GERMaylin & Daniel 260.825<br>
FRAFlorent AMODIO 179.936<br>
GERPeter LIEBERS 179.615<br>
JPNYuzuru HANYU 197.9810<br>
USAJeremy ABBOTT 165.654<br>
UKRYakov GODOROZHA 160.513<br>
GBRMatthew PARR 157.402<br>
ITAPaul Bonifacio PARKINSON 153.941<br>
RUSTatiana & Maxim 283.7910<br>
CANMeagan & Eric 273.109<br>
FRAVanessa & Morgan 257.454<br>
JPNNarumi & Ryuichi 246.563<br>
JPNCathy & Chris 352.003<br>
UKRSiobhan & Dmitri 349.192<br>
CHNXintong &Xun 347.881<br>
RUSYulia LIPNITSKAYA 472.9010<br>
ITACarolina KOSTNER 470.849<br>
JPNMao ASADA 464.078<br>
UKRJulia & Yuri 246.342<br>
GBRStacey & David 244.701<br>
USAMeryl &Charlie 375.9810<br>
CANTessa & Scott 372.989<br>
RUSEkaterina & Dmitri 370.278<br>
FRANathalie & Fabian 369.157<br>
ITAAnna & Luca 364.926<br>
GERNelli & Alexander 358.045<br>
GBRPenny & Nicholas 352.934<br>
USAAshley WAGNER 463.107<br>
CANKaetlyn OSMOND 462.546<br>
GBRJenna MCCORKELL 450.091<br>
The first three letters represent the team.
the rest of the text is the the competitors name.
The last digit is the score the competitor recived.
Code so far:
import java.util.Arrays;
public class project2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] array = new String[41];
String[] info = new String[41];
String[] stats = new String[41];
String[] team = new String[41];
//.txt file location
FileInput fileIn = new FileInput();
fileIn.openFile("C:\\Users\\O\\Desktop\\turn in\\team.txt");
// txt file to array
int i = 0;
String line = fileIn.readLine();
array[i] = line;
i++;
while (line != null) {
line = fileIn.readLine();
array[i] = line;
i++;
}
//Splitting up Info/team/score into seprate arrays
for (int j = 0; j < 40; j++) {
team[j] = array[j].substring(0, 3).trim();
info[j] = array[j].substring(3, 30).trim();
stats[j] = array[j].substring(36).trim();
}
// Random stuff i have been trying
System.out.println(team[1]);
System.out.println(info[1]);
System.out.println(stats[1]);
MyObject ob = new MyObject();
ob.setText(info[0]);
ob.setNumber(7, 23);
ob.setNumber(3, 456);
System.out.println("Text is " + ob.getText() + " and number 3 is " + ob.getNumber(7));
}
}
I'm pretty much stuck at this point because I am not sure how to add each teams score together.
This looks like homework... First of all you need to examine how you are parsing the strings in the file.
You're saying: the first 3 characters are the country, which looks correct, but then you set the info to the 4th through the 30th characters, which isn't correct. You need to dynamically figure out where that ends and the score begins. There is a space between the "info" and the "stats," knowing that you could use String's indexOf function. (http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(int))
Have a look at Maps.
A map is a collection that allows you to get data associated with a key in a very short time.
You can create a Map where the key is a country name, with value being the total points.
example:
Map<String,Integer> totalScore = new HashMap<>();
if (totalScore.containsKey("COUNTRYNAME"))
totalScore.put("COUNTRYNAME", totalScore.get("COUNTRYNAME") + playerScore)
else
totalScore.put("COUNTRYNAME",0)
This will add to the country score if the score exists, otherwise it will create a new totalScore for a country initialized to 0.
Not tested, but should give you some ideas:
public static void main(String... args)
throws Exception {
class Structure implements Comparable<Structure> {
private String team;
private String name;
private Double score;
public Structure(String team, String name, Double score) {
this.team = team;
this.name = name;
this.score = score;
}
public String getTeam() {
return team;
}
public String getName() {
return name;
}
public Double getScore() {
return score;
}
#Override
public int compareTo(Structure o) {
return this.score.compareTo(o.score);
}
}
File file = new File("path to your file");
List<String> lines = Files.readAllLines(Paths.get(file.toURI()), StandardCharsets.UTF_8);
Pattern p = Pattern.compile("(\\d+(?:\\.\\d+))");
List<Structure> structures = new ArrayList<Structure>();
for (String line : lines) {
Matcher m = p.matcher(line);
while (m.find()) {
String number = m.group(1);
String text = line.substring(0, line.indexOf(number) - 1);
double d = Double.parseDouble(number);
String team = text.substring(0, 3);
String name = text.substring(3, text.length());
structures.add(new Structure(team, name, d));
}
}
Collections.sort(structures);
List<Structure> topFive = structures.subList(0, 5);
for (Structure structure : topFive) {
System.out.println("Team: " + structure.getTeam());
System.out.println("Name: " + structure.getName());
System.out.println("Score: " + structure.getScore());
}
}
Just remove <br> from your file.
Loading file into memory
Your string splitting logic looks fine.
Create a class like PlayerData. Create one instance of that class for each row and set all the three fields into that using setters.
Keep adding the PlayerData objects into an array list.
Accumulating
Loop through the arraylist and accumulate the team scores into a hashmap. Create a Map to accumulate the team scores by mapping teamCode to totalScore.
Always store row data in a custom object for each row. String[] for each column is not a good way of holding data in general.
Take a look in File Utils. After that you can extract the content from last space character using String Utils e removing the <br> using it as a key for a TreeMap. Than you can have your itens ordered.
List<String> lines = FileUtils.readLines(yourFile);
Map<String, String> ordered = new TreeMap<>();
for (String s : lines) {
String[] split = s.split(" ");
String name = split[0].trim();
String rate = splt[1].trim().substring(0, key.length - 4);
ordered.put(rate, name);
}
Collection<String> rates = ordered.values(); //names ordered by rate
Of course that you need to adjust the snippet.
Related
currently, I'm doing an assignment that deals with the ArrayList class.
at some point, I need to check of the id of the instructor and make sure that the instructor is not added twice to the ArrayList, so I made a for loop to go through all the id that has been registered and get the id and check if it exists already
the problem is when I use the method " .size()" in the loop, the JVM throws NullPointerException
and I don't know why.
==========================================================================
what I need to read is this:
\\name - id - dateOfBirth - gender - degree - speciality - city - availability
Amanda Smith, 102020, 320101200000, M, PhD, Software Engineering, NewYork, true
=======================================================================
this is the code:
public static void main(String[] args) {
/* NOTE: I HAVE A CLASS CALLED "UniversityMember" THAT IS A SUPERCLASS FOR "Instructor" CLASS */
//declare what I need
ArrayList<UniversityMember> membersList;
Scanner read = new Scanner("inputFile.txt");//the file contains the text above
//First: Split the line everytime the sign ", " shows
String[] line = read.nextLine().split(", ");
//Second: Assign each valuse to its correspondeding variable
String name = line[0];
String id = line[1];
long date = Long.parseLong(line[2]);
Date birthDate = new Date(date);
char gender = line[3].charAt(0);
String degree = line[4];
String specialization = line[5];
String address = line[6];
boolean availability = Boolean.parseBoolean(line[7]);
//check if the Id is registered already
for (int i = 0; i < membersList.size(); i++) { //ERROR OCCURE
if (membersList.get(i) == null) {
break;
}
if (membersList.get(i).id.equals(id)) {
System.out.println("The instructor is registered already, the ID is found in the system.");
System.exit(0);
}
}
//add and make a new object for the constructor
membersList.add(new Instructor(name, id, birthDate, gender, degree, specialization, address, availability));
System.out.println("The instructor is successfully added.");
}//end main
The problem is membersList doesn't exist when you call .size() on it
instead of
ArrayList<UniversityMember> membersList;
you need to initialize it
ArrayList<UniversityMember> membersList = new ArrayList<UniversityMember>();
You need to initialize the ArrayList.
Like that ArrayList membersList = new ArrayList();
After that, in the first size() returns 0 and not null. Remember all data structure must be initialize in java.
You haven't added anything to the membersList then asking for the size for something that has nothing in it.
Example of whats going on
String str;
for(int i = 0; i < str.length(); i++){
System.out.println("hey");
}
also you need to declare the array list like this
ArrayList<Method name> membersList = new ArrayList<Method name>();
also don't forget to import the ArrayList class
import java.util.ArrayList;
nvm I figured out that I haven't initialized my array ( ╥ω╥ )
I'll keep the question for others to be carefull
==================================================
The code after fixing it:
public static void main(String[] args) {
/* NOTE: I HAVE A CLASS CALLED "UniversityMember" THAT IS A SUPERCLASS FOR "Instructor" CLASS */
//declare what I need
ArrayList<UniversityMember> membersList;
Scanner read = new Scanner("inputFile.txt");//the file contains the text above
/* ===== FIXING THE ERROR ======*/
membersList = new ArrayList();
//First: Split the line everytime the sign ", " shows
String[] line = read.nextLine().split(", ");
//Second: Assign each valuse to its correspondeding variable
String name = line[0];
String id = line[1];
long date = Long.parseLong(line[2]);
Date birthDate = new Date(date);
char gender = line[3].charAt(0);
String degree = line[4];
String specialization = line[5];
String address = line[6];
boolean availability = Boolean.parseBoolean(line[7]);
//check if the Id is registered already
for (int i = 0; i < membersList.size(); i++) {
if (membersList.get(i) == null) {
break;
}
if (membersList.get(i).id.equals(id)) {
System.out.println("The instructor is registered already, the ID is found in the system.");
System.exit(0);
}
}
//add and make a new object for the constructor
membersList.add(new Instructor(name, id, birthDate, gender, degree, specialization, address, availability));
System.out.println("The instructor is successfully added.");
}//end main
The overall project is creating a system manager for airports. It keeps track of airports, flights, seating sections, seats and other relevent info for each of those catagories. The initial system is set up by importing from a file that's formatted a certain way. I'm having problems parsing the file properly to set up the initial system. the data is parsed from the file and used as method parameters to create the objects: Airport, Airline, Flight, FlightSection, and Seat.
the formatting is:
[list-of-airport-codes] {list-of-airlines}
list-of-airport-codes ::= comma-separated strings
list-of-airlines ::= airline-name1[flightinfo-list1], airline-name2[flightinfo-list2], airlinename3[flightinfo-list3], …
flightinfo-list ::= flightID1|flightdate1|originAirportCode1|destinationAirportCode1[flightsectionlist1], flightID2|flightdate2|originAirportCode2|destinationAirportCode2[flightsection-list2], …
flightdate ::= year, month, day-of-month, hours, minutes
flightsection-list ::= sectionclass: seat-price: layout: number-of-rows, …
sectionclass ::= F, B, E (for first class, business class, economy class)
layout ::= S, M, W (different known seating layouts)
example:
[DEN,NYC,SEA,LAX]{AMER[AA1|2018,10,8,16,30|DEN|LAX[E:200:S:4,F:500:S:2],
AA2|2018,8,9,7,30|LAX|DEN[E:200:S:5,F:500:S:3], …], UNTD[UA21|2018,11,8,12,30|NYC|SEA[E:300:S:6,F:800:S:3], UA12|2018,8,9,7,30|SEA|DEN[B:700:S:5, F:1200:S:2], …], FRONT[…], USAIR[…]}
I tried brute forcing it using a combination of delimiters and while loops. The code successfully creates the Airports, first Airline and Flighsections, but when it gets to creating the second airline it crashes, because i'm not looping properly, and having a hard time getting it right. My code for it as of now, is a mess, and if you're willing to look at it, I would appreciate any constructive input. My question is what would be a better way to approach this? A different design approach? Maybe a smarter way to use the delimiters?
Thanks in advance for your help!!
here's what i've tried.
private void readFile(File file){
System.out.println("reading file");
Scanner tempScan;
String result;
String temp = "";
scan.useDelimiter("\\[|\\{");
try{
// AIRPORTS
result = scan.next();
tempScan = new Scanner(result);
tempScan.useDelimiter(",|\\]");
while(tempScan.hasNext()){
temp = tempScan.next();
sysMan.createAirport(temp);
}
tempScan.close();
/* AIRLINE
* FLIGHT
* FLIGHTSECTION
*/
do{
// AIRLINE (loop<flight & fsection>)
result = scan.next();
sysMan.createAirline(result);
// FLIGHT
result = scan.next();
tempScan = new Scanner(result);
do{
tempScan.useDelimiter(",|\\|");
ArrayList flightInfo = new ArrayList();
while(tempScan.hasNext()){
if(tempScan.hasNextInt()){
flightInfo.add(tempScan.nextInt());
} else {
flightInfo.add(tempScan.next());
}
}
tempScan.close();
sysMan.createFlight(sysMan.getLastAddedAirline(),(String)flightInfo.get(0), (int)flightInfo.get(1), (int)flightInfo.get(2), (int)flightInfo.get(3), (int)flightInfo.get(4), (int)flightInfo.get(5), (String)flightInfo.get(6), (String)flightInfo.get(7));
// FLIGHTSECTION (loop<itself>)
result = scan.next();
tempScan = new Scanner(result);
tempScan.useDelimiter(",|:|\\]");
ArrayList sectInfo = new ArrayList();
int i = 1;
while(!temp.contains("|")){
if(tempScan.hasNextInt()){
sectInfo.add(tempScan.nextInt());
} else {
temp = tempScan.next();
if(temp.equals(""))
break;
char c = temp.charAt(0);
sectInfo.add(c);
}
if(i == 4){
sysMan.createSection(sysMan.getLastAddedAirline(), sysMan.getLastAddedFlightID(), (char)sectInfo.get(0), (int)sectInfo.get(1), (char)sectInfo.get(2), (int)sectInfo.get(3));
i = 1;
sectInfo = null;
sectInfo = new ArrayList();
continue;
}
i++;
}
}while(!temp.equals("\\s+"));
}while(!temp.contains("\\s+"));
}catch(NullPointerException e){
System.err.println(e);
}
}
I'd rather chunk it down by regexp mathing the outer bounds, have a look, I took it a couple of levels broken.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Tokeni {
static String yolo = "[DEN,NYC,SEA,LAX]{AMER["
+ "AA1|2018,10,8,16,30|DEN|LAX[E:200:S:4,F:500:S:2],"
+ "AA2|2018,8,9,7,30|LAX|DEN[E:200:S:5,F:500:S:3]],"
+ "UNTD[UA21|2018,11,8,12,30|NYC|SEA[E:300:S:6,F:800:S:3],"
+ "UA12|2018,8,9,7,30|SEA|DEN[B:700:S:5, F:1200:S:2]]}";
public static void main(String[] args) {
Matcher airportCodesMatcher = Pattern.compile("\\[(.*?)\\]").matcher(yolo);
airportCodesMatcher.find();
String[] airportCodes = airportCodesMatcher.group(1).split(",");
Matcher airLinesMatcher = Pattern.compile("\\{(.*?)\\}").matcher(yolo);
airLinesMatcher.find();
String airLinesStr = airLinesMatcher.group(1);
System.out.println(airLinesStr);
Pattern airLinePattern = Pattern.compile("\\D+\\[(.*?)\\]\\]");
Matcher airLineMatcher = airLinePattern.matcher(airLinesStr);
while( airLineMatcher.find() ) {
String airLineStr = airLineMatcher.group(0).trim();
if(airLineStr.startsWith(",")) {
airLineStr = airLineStr.substring(1, airLineStr.length()).trim();
}
System.out.println(airLineStr);
Matcher airLineNameMatcher = Pattern.compile("[A-Z]+").matcher(airLineStr);
airLineNameMatcher.find();
String airLineName = airLineNameMatcher.group(0).trim();
System.out.println(airLineName);
airLineStr = airLineStr.substring(airLineStr.indexOf("[")+1, airLineStr.length());
Matcher airLineInfoMatcher = Pattern.compile("\\D+(.*?)\\]").matcher(airLineStr);
while(airLineInfoMatcher.find()) {
String airLineInfoStr = airLineInfoMatcher.group(0).trim();
if(airLineInfoStr.startsWith(",")) {
airLineInfoStr = airLineInfoStr.substring(1, airLineInfoStr.length()).trim();
}
System.out.println(airLineInfoStr);
}
}
}
}
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).
How can I search element in arraylist and display it? Example is the user wants to search the code A25 Then it will print the whole content on that arraylist that he search only and the output is A25 CS 212 Data Structures 3.
Subject CS212 = new Subject("A25","\t\tCS 212","\t\tData Structures\t\t\t\t",units);
Subject IT312 = new Subject("A26","\t\tIT 312","\t\tData Base Management System 2\t\t",units);
Subject IT313 = new Subject("A27","\t\tIT 312","\t\tData Base Management System 2\t\t",units);
Subject CS313 = new Subject("A29","\t\tCS 313","\t\tDigital Designt\t\t\t\t",units);
Subject Disc = new Subject("A30","\t\tIT 212","\t\tDiscrete Structurest\t\t",units);
Subject A31 = new Subject("A31","\t\tIT 212","\t\tDiscrete Structurest\t\t",units);
Subject Engl3 = new Subject("984","\t\tEngl 3","\t\tSpeech and oral Communicationt\t\t",units);
Subject Theo3 = new Subject("582","\t\tTheo 3","\t\tChrist and Sacramentst\t\t",units);
Subject Stat = new Subject("470","\t\tStata1","\t\tProbablility and Statisticst\t\t",units);
Subject Dota = new Subject("999","\t\tDota 2","\t\tDota Guide\t\t\t\t",units);
ArrayList<Subject> arrList = new ArrayList<Subject>();
arrList.add(CS212);
arrList.add(IT312);
arrList.add(IT313);
arrList.add(CS313);
arrList.add(Disc);
arrList.add(A31);
arrList.add(Engl3);
arrList.add(Theo3);
arrList.add(Stat);
arrList.add(Dota);
//User input that he wants to search
for(int i = 0; i < 3; i++,num++)
{
System.out.print("\t\t"+num +". ");
codeNo[i] = scan.next();
String output = Character.toUpperCase(codeNo[i].charAt(0)) + codeNo[i].substring(1);
codeNo[i] = output;
}
// This is what I tried but it doesn't work Idk why
for (Subject s : arrList) {
for(int i =0; i < codeNo.length; i++)
if (s.equals(codeNo[i])) {
System.out.println("\t\t\t"+s);
}
}
public Subject(String codeNo, String subjectID, String title , int unit)
{
//Constructor . .
}
//Desired output
Code to search
A25
A26
A27
output
A25 CS 212 Data Structures 3
A26 IT 312 Data Base Management System 2 3
A27 IT 312 Data Base Management System 2 3
You are trying to search an arraylist of subjects, you need to write a small function to compare the code string to the corresponding string of the class. You can do this by adding this to your subject class.
Example :
#Override
public boolean equals(String code) {
return code.equals(this.<compare to member>);
}
and change the compare to member that needs to match the code that you match.
EDIT : Easier way to do is to just change your existing code to :
if (s.code.equals(codeNo[i])) //assuming your code class member is a public string
I have a csv dataset like this:
A, 10, USA
B,30, UK
C,4,IT
A,20,UK
B,10,USA
I want to read this csv lines and provide the following output:
A has ran 30 miles with average of 15.
B has ran 30 miles with average of 20.
C has ran 4 miles with average of 4.
I want to achieve this in Java. I have done this in C# by using Linq:
var readlines = File.ReadAllLines(filename);
var query = from lines in readlines
let data = lines.Split(',')
select new
{
Name = data[0],
Miles = data[1],
};
var values = query.GroupBy(x => new {x.Name}).Select(group => new { Person = group.Key, Events = group.Sum(g =>Convert.ToDouble(g.Miles)) ,Count = group.Count() });
I am looking to do this in Java, and I am not sure if I can do this without using any third party library or not? Any ideas?
So far, my code looks like this in Java:
CSVReader reader = new CSVReader(new FileReader(filename));
java.util.List<String[]> content = reader.readAll();
String[] row = null;
for(Object object:content)
{
row = (String[]) object;
String Name = row[0];
String Miles = row[1];
System.out.printf("%s has ran %s miles %n",Name,Miles);
}
reader.close();
}
I am looking for a nice way to get the total milage value for each name to calculate for the average.
As a C# developer, it is hard sometimes not to miss the features of linq. But as Farlan suggested you could do something like this:
CSVReader reader = new CSVReader(new FileReader(filename));
java.util.List<String[]> content = reader.readAll();
Map<String, Group> groups = new HashMap<>();
for(String[] row : content)
{
String Name = row[0];
String Miles = row[1];
System.out.printf("%s has ran %s miles %n", Name, Miles);
if (groups.containsKey(Name)){
groups.get(Name).Add(Double.valueOf(Miles));
} else {
Group g = new Group();
g.Add(Double.valueOf(Miles));
groups.put(Name, g);
}
}
reader.close();
for (String name : groups.keySet())
{
System.out.println(name + " ran " + groups.get(name).total() + " with avg of " + groups.get(name).average());
}
}
class Group {
private List<Double> miles;
public Group()
{
miles = new ArrayList<>();
}
public Double total(){
double sum = 0;
for (Double mile : miles)
{
sum += mile;
}
return sum;
}
public Double average(){
if (miles.size() == 0)
return 0d;
return total() / miles.size();
}
public void Add(Double m){
miles.add(m);
}
}
Use Java's BufferedReader class:
BufferedReader in = new BufferedReader(new FileReader("your.csv"));
String line;
while ( (line = in.readLine()) != null) {
String [] fields = line.split(",");
System.out.println(fields[0] + " has ran " + fields[1] + " miles with average " + fields[2]);
}
There are quite a few ways to do this, some long-winded approaches, some shorter. The issue is that Java can be very verbose for doing simple tasks, so the better approaches can be a bit uglier.
The example below shows you exactly how to achieve this, par the printing. Bear in mind however, it might not be the best approach but I feel its more of the easier ones to read and comprehend.
final File csvFile = new File("filename.csv");
final Scanner reader = new Scanner(csvFile);
final Map<String, Integer> info = new HashMap<>(); //Store the data
//Until there is are no more lines, continue
while (reader.hasNextLine()) {
final String[] data = reader.nextLine().split(","); // data[0] = A. [1] = 10. [2] = USA
final String alpha = data[0];
if (!info.containsKey(alpha)) {
info.put(alpha, Integer.parseInt(data[1]));
} else {
int miles = info.get(alpha);
info.put(alpha, miles + Integer.parseInt(data[1]));
}
}
reader.close();
The steps involved are simple:
Step 1 - Read the file.
By passing a File into the Scanner object, you set the target parsing to the File and not the console. Using the very neat hasNextLine() method, you can continually read each line until no more exist. Each line is then split by a comma, and stored in a String array for reference.
Step 2 - Associating the data.
As you want to cumulatively add the integers together, you need a way to associate already passed in letters with the numbers. A heavyweight but clean way of doing this is to use a HashMap. The Key which it takes is going to be a String, specifically A B or C. By taking advantage of the fact the Key is unique, we can use the O(1) containsKey(String) method to check if we've already read in the letter. If its new, add it to the HashMap and save the number with it. If however, the letter has been seen before, we find the old value, add it with the new one and overwrite the data inside the HashMap.
All you need to do now is print out the data. Feel free to take a different approach, but I hope this is a clear example of how you CAN do it in Java.
Maybe you could try this Java library: https://code.google.com/p/qood/
It handles data without any getter/setters, so it's more flexible than LINQ.
in your case, file "D:/input.csv" has 3 columns:
NAME,MILES,COUNTRY
A, 10, USA
B,30, UK
C,4,IT
A,20,UK
B,10,USA
the query code would be:
final QModel raw = QNew.modelCSV("D:/input.csv")
.debug(-1);//print out what read from CSV
raw.query()
.selectAs("OUTPUT",
"CONCAT(NAME,' has ran ',SUM(MILES),' miles with average of ',MEAN(MILES),'.')")
.groupBy("NAME")
.result().debug(-1)//print out the result
.to().fileCSV("D:/output.csv", "UTF-8");//write to another CSV file