I want to check and verify that all of the contents in the ArrayList are similar to the value of a String variable. If any of the value is not similar, the index number to be printed with an error message like (value at index 2 didn't match the value of expectedName variable).
After I run the code below, it will print all the three indexes with the error message, it will not print only the index number 1.
Please note that here I'm getting the data from CSV file, putting it into arraylist and then validating it against the expected data in String variable.
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
public class ValidateVideoDuration {
private static final String CSV_FILE_PATH = "C:\\Users\\videologs.csv";
public static void main(String[] args) throws IOException {
String expectedVideo1Duration = "00:00:30";
String expectedVideo2Duration = "00:00:10";
String expectedVideo3Duration = "00:00:16";
String actualVideo1Duration = "";
String actualVideo2Duration = "";
String actualVideo3Duration = "";
ArrayList<String> actualVideo1DurationList = new ArrayList<String>();
ArrayList<String> actualVideo2DurationList = new ArrayList<String>();
ArrayList<String> actualVideo3DurationList = new ArrayList<String>();
try (Reader reader = Files.newBufferedReader(Paths.get(CSV_FILE_PATH));
CSVParser csvParser = new CSVParser(reader,
CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());) {
for (CSVRecord csvRecord : csvParser) {
// Accessing values by Header names
actualVideo1Duration = csvRecord.get("Video 1 Duration");
actualVideo1DurationList.add(actualVideo1Duration);
actualVideo2Duration = csvRecord.get("Video 2 Duration");
actualVideo2DurationList.add(actualVideo2Duration);
actualVideo3Duration = csvRecord.get("Video 3 Duration");
actualVideo3DurationList.add(actualVideo3Duration);
}
}
for (int i = 0; i < actualVideo2DurationList.size(); i++) {
if (actualVideo2DurationList.get(i) != expectedVideo2Duration) {
System.out.println("Duration of Video 1 at index number " + Integer.toString(i)
+ " didn't match the expected duration");
}
}
The data inside my CSV file look like the following:
video 1 duration, video 2 duration, video 3 duration
00:00:30, 00:00:10, 00:00:16
00:00:30, 00:00:15, 00:00:15
00:00:25, 00:00:10, 00:00:16
Don't use == or != for string compare. == checks the referential equality of two Strings and not the equality of the values. Use the .equals() method instead.
Change your if condition to if (!actualVideo2DurationList.get(i).equals(expectedVideo2Duration))
Related
I am trying to read a text file and store with a hashmap. The file contains information like this:
1946-01-12;13:00:00;0.3;G
1946-01-12;18:00:00;-2.8;G
1946-01-13;07:00:00;-6.2;G
1946-01-13;13:00:00;-4.7;G
1946-01-13;18:00:00;-4.3;G
1946-01-14;07:00:00;-1.5;G
1946-01-14;13:00:00;-0.2;G
I want to store the dates as keys and then "13:00:00;0.3;G" as value, where 13:00 is time, 0.3 is temperature and G represent a quality code. I wonder if this is even possbile since many rows in the file has the same date? I already wrote a code for storing the data in a list, but now I want to store it in a map instead. My old code looks like this:
/**
* Provides methods to retrieve temperature data from a weather station file.
*/
public class WeatherDataHandler {
private List<Weather> weatherData = new ArrayList<>();
public void loadData(String filePath) throws IOException {
List<String> fileData = Files.readAllLines(Paths.get("filepath"));
for(String str : fileData) {
List<String> parsed = parseData(str);
LocalDate date = LocalDate.parse(parsed.get(0));
LocalTime time = LocalTime.parse(parsed.get(1));
double temperature = Double.parseDouble(parsed.get(2));
String quality = parsed.get(3);
//new Weather object
Weather weather = new Weather(date, time, temperature, quality);
weatherData.add(weather);
}
}
private List<String> parseData(String s) {
return Arrays.asList(s.split(";"));
}
I got stuck when implementing the hashmap. I started with some code below, but I do not know how to loop over a sequence of dates. What is the simplest way to store the data from the file in a map?
public class WeatherDataHandler {
public void loadData(String filePath) throws IOException {
Map<LocalDate, String> map =new HashMap<LocalDate, String>();
BufferedReader br = new BufferedReader(new FileReader("filepath"));
String line="";
int i=0;
while (line != null) {
line = br.readLine();
map.put(i,line);
i++;
}
String date="";
String time="";
String temperature="";
String quality="";
for(int j=0;j<map.size();j++){
if(!(map.get(j)== null)){
String[] getData=map.get(j).toString().split("\\,");
date = getData[0];
time = getData[1];
temperature = getData[2];
quality = getData[3];
}
}
}
Using the stream API you can create a map where the key is the date and the [map] value is a list.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class WeatherDataHandler {
public static void main(String[] args) {
Path path = Paths.get("filepath");
try {
Map<String, List<String>> map = Files.lines(path)
.collect(Collectors.groupingBy(line -> line.split(";", 2)[0]));
map.entrySet()
.stream()
.forEach(entry -> System.out.printf("%s = %s%n", entry.getKey(), entry.getValue()));
}
catch (IOException x) {
x.printStackTrace();
}
}
}
Method lines() in class java.nio.file.Files creates a stream where each stream element is a single line of the file being read.
Method split() splits the line into a two element array (because of the second argument which is the number 2).
The first array element, i.e. the date, becomes the [map] key and the rest of the line becomes the [map] value.
Whenever a duplicate key is encountered, the value is appended to the existing value creating a list. Hence the type parameters for the map are String for the [map] key and List<String> for the [map] value.
Running the above code on your sample data yields:
1946-01-14 = [1946-01-14;07:00:00;-1.5;G, 1946-01-14;13:00:00;-0.2;G]
1946-01-12 = [1946-01-12;13:00:00;0.3;G , 1946-01-12;18:00:00;-2.8;G]
1946-01-13 = [1946-01-13;07:00:00;-6.2;G , 1946-01-13;13:00:00;-4.7;G, 1946-01-13;18:00:00;-4.3;G ]
I have several bank statements from our users. I am trying to figure out a way to parse the rows of transactions. I have used PDFBox previously using TextArea, TextStripper, but i am not sure how to proceed with bank statements since they will have an undetermined number of rows and the rows may or maynot be of fixed size.
i wrote just such a parser to parse our chase pdf credit card statements, to speed up the tax-preparation time, with the help of an open source project called Apache Tika.
just need to include tika and pdf parser in your pom.xml dependencies:
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.17</version>
</dependency>
the PDF extractor is fairly straightforward also:
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class PdfExtractor {
private static Logger logger = LoggerFactory.getLogger(PdfExtractor.class);
public static void main(String args[]) throws Exception {
StopWatch sw = new StopWatch();
List<String> files = new ArrayList<>();
files.add("C:/Users/m/Downloads/20170115.pdf");
files.add("C:/Users/m/Downloads/20170215.pdf");
files.add("C:/Users/m/Downloads/20170315.pdf");
files.add("C:/Users/m/Downloads/20170415.pdf");
files.add("C:/Users/m/Downloads/20170515.pdf");
files.add("C:/Users/m/Downloads/20170615.pdf");
files.add("C:/Users/m/Downloads/20170715.pdf");
files.add("C:/Users/m/Downloads/20170815.pdf");
files.add("C:/Users/m/Downloads/20170915.pdf");
files.add("C:/Users/m/Downloads/20171015.pdf");
files.add("C:/Users/m/Downloads/20171115.pdf");
files.add("C:/Users/m/Downloads/20171215.pdf");
files.add("C:/Users/m/Downloads/20180115.pdf");
InputStream is;
List<ChasePdfParser.ChaseRecord> full = new ArrayList<>();
for (String fileName : files) {
logger.info("Now processing " + fileName);
is = new FileInputStream(fileName);
ContentHandler contenthandler = new BodyContentHandler();
Metadata metadata = new Metadata();
PDFParser pdfparser = new PDFParser();
pdfparser.parse(is, contenthandler, metadata, new ParseContext());
String data = contenthandler.toString();
List<ChasePdfParser.ChaseRecord> chaseRecords = ChasePdfParser.parse(data);
full.addAll(chaseRecords);
is.close();
}
logger.info("Total processing time: " + PrettyPrinter.toMsSoundsGood(sw.getTime()));
full.forEach(cr -> System.err.println(cr.date + "|" + cr.desc + "|" + cr.amt));
}
}
The line parser also fairly straight-forward, since each line has all the necessary info, it's easy to parse it:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ChasePdfParser {
private static Logger logger = LoggerFactory.getLogger(ChasePdfParser.class);
private static int FOR_TAX_YEAR = 2017;
private static String YEAR_EXTENSION = "/" + FOR_TAX_YEAR;
private static DateTimeFormatter check = DateTimeFormatter.ofPattern("MM/dd/uuuu");
private static List<String> exclusions = new ArrayList<>(Arrays.asList("Payment Thank You", "AUTOMATIC PAYMENT"));
public static List<ChaseRecord> parse(String data) {
List<ChaseRecord> l = new ArrayList<>();
for (String line : data.split("\n")) {
if (line.isEmpty()) continue;
String[] split = line.split("\\s");
if (split == null || split.length == 0) continue;
String test = split[0];
if (!isMMDD(test)) continue;
if(skip(line)) continue;
if (split.length < 4) continue;
ChaseRecord cr = new ChaseRecord();
cr.date = extractDate(test);
try {
String last = split[split.length - 1];
last = last.replaceAll(",", "");
cr.amt = Double.parseDouble(last);
} catch (NumberFormatException e) {
e.printStackTrace();
}
cr.desc = String.join(" ", Arrays.copyOfRange(split, 1, split.length - 1));
cr.desc = cr.desc.replaceAll("\\s\\s+", " ");
l.add(cr);
}
return l;
}
private static boolean skip(String s) {
if (s == null || s.isEmpty()) {
return true;
}
for (String e : exclusions) {
if (s.contains(e)) {
return true;
}
}
return false;
}
protected static LocalDate extractDate(String s) {
if (!isMMDD(s)) {
return null;
}
LocalDate localDate = LocalDate.parse(s + YEAR_EXTENSION, check);
return localDate;
}
public static boolean isMMDD(String s) {
if (s == null || s.isEmpty() || s.length() != 5) {
return false;
}
try {
s += YEAR_EXTENSION;
LocalDate.parse(s, check);
return true;
} catch (Exception e) {
return false;
}
}
public static class ChaseRecord {
public LocalDate date;
public String desc;
public Double amt;
#Override
public String toString() {
return "ChaseRecord{" +
"date=" + date +
", desc='" + desc + '\'' +
", amt=" + amt +
'}';
}
}
}
Late to the party. You can also use pdftotext as a workaround. Everyone once in a great while it will miss out an amount of currency, particularly in the upper right of the table.
As you'd expect, you'll join the text on newlines and then start chopping the lines into lists, thence to write it to a tsv. The approach looks like this:
HTH.
import csv
import pdftotext
import re
from datetime import *
import os
import pandas as pd
# compile directory ref:
path='path to directory'
directory = os.fsencode(path)
# https://stackoverflow.com/questions/42202872/how-to-convert-list-to-row-dataframe-with-pandas
column_list = ['filesource','filedate','eventdate','description','bankcategory','amount']
filelist=[]
# an example of how to scrape chase statement pdf into list of lists:
def process_pdf_data(filename,filesource,filedate):
# trying with pdftotext
# print('starting pdf content scrape', file)
with open(filename, "rb") as f:
pdf = pdftotext.PDF(f)
pdf_join="\n".join(pdf)
pdf_array=pdf_join.split('\n')
# print(pdf_array)
startint=0
line=''
# at this point, the pdf_array is just a list of strings read serially from the pdf in succession down the page.
while line!='Account activity' and startint<=1000:
line=pdf_array[startint]
startint+=1
startint-=1 # bc it still gets incremented on exit above
# drop data before 'Account activity' as we won't need it.
del pdf_array[:startint]
# print(pdf_array)
# set pattern for date detection
# https://www.programiz.com/python-programming/regex
# https://docs.python.org/3/library/re.html
pattern=re.compile("^([A-Z]|[a-z]){3} [0-9]{1,2}, [0-9]{4}$") # test pattern for regex eval of date
startint=0 # use for test exit limits
# print('entering pdf content eval', file)
while startint<len(pdf_array):
# if string has certain date format:
# if it doesn't have this conversion then it's suspect and maybe write it to log
# print(startint,pdf_array[startint])
if pattern.match(pdf_array[startint])!=None:
# transform it to date
# https://docs.python.org/3/library/datetime.html
datestr=datetime.strptime(pdf_array[startint], '%b %d, %Y').date().isoformat()
# print('pattern match',datestr)
# look ahead and keep next few strings:
description=pdf_array[startint+2]
bankcategory=pdf_array[startint+4]
amount=''
if '$' in pdf_array[startint+6]:
amount=pdf_array[startint+6] # will mess with $/string type conversion downstream, when combining sources
# write to list of lists
templist=[]
templist.append(filesource)
templist.append(filedate)
templist.append(datestr)
templist.append(description)
templist.append(bankcategory)
templist.append(amount)
# print(templist)
filelist.append(templist)
startint+=1
process_pdf_data(,,)
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).
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
I would like to take this format:
//Game, Team, Player, Position, Order, Sub----Not part of file
331027,24,7912,CF,1,1
331028,22,7913,P,1,1
331028,22,5909,1B,2,1
331028,22,8394,P,2,2
And display this data(order) based on a higher number for sub in a given order and the output will become:
331027,24,7912,CF,1 //player 7912 goes first for team 24
331028,22,7913,P,1 //player 7913 goes first for team 22
331028,22,8394,P,2 // player 8394 goes second for team 22 because he/she has higher 'Sub' order
UPDATE:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class BattingOrder {
String game_ID;
String team_ID;
String player_ID;
String position;
String battingOrder;
String subOrder;
public BattingOrder(String game, String team, String player, String place,
String batter, String sub) {
game_ID = game;
team_ID = team;
player_ID = player;
position = place;
battingOrder = batter;
subOrder = sub;
}
#Override
public String toString() {
return game_ID + "," + team_ID + "," + player_ID + "," + position + ","
+ battingOrder;
}
public static void main(String[] args) throws IOException {
FileInputStream fstream = new FileInputStream(
"BatterInfo.txt");
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
List<BattingOrder> sortList = new ArrayList<BattingOrder>();
for (String line; (line = br.readLine()) != null;) {
String delims = "[,]";
String[] parsedData = line.split(delims);
sortList.add(new BattingOrder(parsedData[0], parsedData[1],
parsedData[2], parsedData[3], parsedData[4], parsedData[5]));
}
for (BattingOrder order : sortList) {
System.out.println(order);
}
br.close();
}
}
Current Output:
331027,24,7912,CF,1
331028,22,7913,P,1
331028,22,5909,1B,2 //This should be replaced by bottom 'string' because the subOrder is higher.
331028,22,8394,P,2
I want:
331027,24,7912,CF,1
331028,22,7913,P,1
331028,22,8394,P,2
How might the logic look in pseudo-code?
From http://www.mkyong.com/java/how-to-sort-an-arraylist-in-java/ and http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/ and the above answer from Java Devil
I think the best method would be to put each BattingOrder object into a collection i.e. ArrayList and use Collections.sort
List<BattingOrder> unsortList = new ArrayList<BattingOrder>();
Add a constructor to BattingOrder or just manually set the values inside your for loop in main to either split the input string from the file or accept the preparsed values
then after the for loop is complete call Collections.sort and pass in a custom Comparator, you have most of the required code commented out should be no issue.
for (String line; (line = br.readLine()) != null;) {
// String delims = "[,]";
// String[] parsedData = line.split(delims);
//Split and assign the values to a new BattingOrder object here either in a
//constructor for BattingObject or here and pass in the values from the file
unsortList.add(new BattingOrder(line));
}
After the loop is complete call our custom sort function
Collections.sort(unsortList ,new Comparator<BattingOrder>(){
#Override
public int compare(BattingOrder one, BattingOrder two) {
Integer orderOne = Integer.parseInt(one.battingOrder);
Integer orderTwo = Integer.parseInt(two.battingOrder);
//ascending order
return orderOne.compareTo(orderTwo);
//descending order
//return orderTwo.compareTo(orderOne);
}
});
and bam should be sorted
I can't test this code atm at work no Java compiler but it should be close if not correct
Good luck ;)
Edit 3 (Clarification)
I was hoping you might add some more detail overnight, (Original input with index)
Index Pos Order Sub
1 CF 1 1
2 P 1 1
3 1B 2 1
4 P 2 2
Atm you don't have sufficient sort logic, disappearing index 3 is possible with the lower subOrder but 1 & 2 are interchangeable as they both have subOrder of 1 and order of 1 so whichever was read in first will be at the top of the list i think.
This code should sort them in some random order (Determined by the order they are read in by basically)
then will delete any that have a matching battingOrder and a lower subOrder
I hope thats close to what you want anyway the sort is pretty good just not great logic the delete isn't very efficient but its all I have to go on atm
All the casts could be removed by storing the integers as ints rather than strings
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class BattingOrder
{
String game_ID;
String team_ID;
String player_ID;
String position;
String battingOrder;
String subOrder;
public BattingOrder(String game, String team, String player, String place, String batter, String sub) {
game_ID = game;
team_ID = team;
player_ID = player;
position = place;
battingOrder = batter;
subOrder = sub;
}
#Override
public String toString()
{
return game_ID + "," + team_ID + "," + player_ID + "," + position + "," + battingOrder;
}
public static void main(String[] args) throws IOException
{
FileInputStream fstream = new FileInputStream("BatterInfo.txt");
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String delims = "[,]";
List<BattingOrder> battingOrders = new ArrayList<BattingOrder>();
for (String line; (line = br.readLine()) != null;)
{
String[] parsedData = line.split(delims);
battingOrders.add(new BattingOrder(parsedData[0], parsedData[1], parsedData[2], parsedData[3], parsedData[4], parsedData[5]));
}
br.close();
System.out.println("Unordered");
for (BattingOrder order : battingOrders)
{
System.out.println(order);
}
Collections.sort(battingOrders ,new Comparator<BattingOrder>(){
#Override
public int compare(BattingOrder one, BattingOrder two)
{
if(one.battingOrder.equals(two.battingOrder))
{
Integer subOrderOne = Integer.parseInt(one.subOrder);
Integer subOrderTwo = Integer.parseInt(two.subOrder);
return subOrderOne.compareTo(subOrderTwo);
}
Integer orderOne = Integer.parseInt(one.battingOrder);
Integer orderTwo = Integer.parseInt(two.battingOrder);
return orderOne.compareTo(orderTwo);
}
});
System.out.println("Ordered");
for (BattingOrder order : battingOrders)
{
System.out.println(order);
}
List<BattingOrder> toDelete = new ArrayList<BattingOrder>();
for (BattingOrder one : battingOrders)
{
for (BattingOrder two : battingOrders)
{
if(one.battingOrder.equals(two.battingOrder))
{
Integer subOrderOne = Integer.parseInt(one.subOrder);
Integer subOrderTwo = Integer.parseInt(two.subOrder);
if(subOrderOne < subOrderTwo)
{
toDelete.add(one);
}
else if(subOrderOne > subOrderTwo)
{
toDelete.add(two);
}
}
}
}
battingOrders.removeAll(toDelete);
System.out.println("Final");
for (BattingOrder order : battingOrders)
{
System.out.println(order);
}
}
}
You will need to read in all the lines from the text file first and then sort them.
As you read each line store it into a List of either Strings or better yet would be to create an object which represents each line - Which you pretty much have here already. So for each line you would want split by comma as you have comments and assign the values to a new instance of your object then add this to a list.
You can then sort the list using a comparator on these objects in the list using something like this
Collections.sort(yourList,new Comparator<BattingOrder>(){
#Override
public int compare(BattingOrder b1, BattingOrder b2)
{
//Your comparison code goes here
}
});