Prinitng matching information from 2 files in Java - java

I am trying to write a program that checks two files and prints the common contents from both the files.
Example of the file 1 content would be:
James 1
Cody 2
John 3
Example of the file 2 content would be:
1 Computer Science
2 Chemistry
3 Physics
So the final output printed on the console would be:
James Computer Science
Cody Chemistry
John Physics
Here is what I have so far in my code:
public class Filereader {
public static void main(String[] args) throws Exception {
File file = new File("file.txt");
File file2 = new File("file2.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
BufferedReader reader2 = new BufferedReader(new FileReader(file2));
String st, st2;
while ((st = reader.readLine()) != null) {
System.out.println(st);
}
while ((st2 = reader2.readLine()) != null) {
System.out.println(st2);
}
reader.close();
reader2.close();
}
}
I am having trouble in figuring out how to match the file contents, and print only the student name and their major by matching the student id in each of the file. Thanks for all the help.

You can use the other answers and make an object to every file, like tables in databases.
public class Person{
Long id;
String name;
//getters and setters
}
public class Course{
Long id;
String name;
//getters and setters
}
Them you have more control with your columns and it is simple to use.
Further you will use an ArrayList<Person> and an ArrayList<Course> and your relation can be a variable inside your objects like courseId in Person class or something else.
if(person.getcourseId() == course.getId()){
...
}
Them if the match is the first number of the files use person.getId() == course.getId().
Ps: Do not use split(" ") in your case, because you can have other objects with two values i.e 1 Computer Science.

What you want is to organize your text file data into map, then merge their data. This will work even if your data are mixed, not in order.
public class Filereader {
public static void main(String[] args) throws Exception {
File file = new File("file.txt");
File file2 = new File("file2.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
BufferedReader reader2 = new BufferedReader(new FileReader(file2));
String st, st2;
Map<Integer, String> nameMap = new LinkedHashMap<>();
Map<Integer, String> majorMap = new LinkedHashMap<>();
while ((st = reader.readLine()) != null) {
System.out.println(st);
String[] parts = st.split(" "); // Here you got ["James", "1"]
String name = parts[0];
Integer id = Integer.parseInt(parts[1]);
nameMap.put(id, name);
}
while ((st2 = reader2.readLine()) != null) {
System.out.println(st2);
String[] parts = st2.split(" ");
String name = parts[1];
Integer id = Integer.parseInt(parts[0]);
majorMap.put(id, name);
}
reader.close();
reader2.close();
// Combine and print
nameMap.keySet().stream().forEach(id -> {
System.out.println(nameMap.get(id) + " " + majorMap.get(id));
})
}
}

You should read these files at the same time in sequence. This is easy to accomplish with a single while statement.
while ((st = reader.readLine()) != null && (st2 = reader2.readLine()) != null) {
// print both st and st2
}
The way your code is written now, it reads one file at a time, printing data to the console from each individual file. If you want to meld the results together, you have to combine the output of the files in a single loop.
Given that the intention may also be that you have an odd-sized file in one batch but you do have numbers to correlate across, or the numbers may come in a nonsequential order, you may want to store these results into a data structure instead, like a List, since you know the specific index of each of these values and know where they should fit in.

Combining the NIO Files and Stream API, it's a little simpler:
public static void main(String[] args) throws Exception {
Map<String, List<String[]>> f1 = Files
.lines(Paths.get("file1"))
.map(line -> line.split(" "))
.collect(Collectors.groupingBy(arr -> arr[1]));
Map<String, List<String[]>> f2 = Files
.lines(Paths.get("file2"))
.map(line -> line.split(" "))
.collect(Collectors.groupingBy(arr -> arr[0]));
Stream.concat(f1.keySet().stream(), f2.keySet().stream())
.distinct()
.map(key -> f1.get(key).get(0)[0] + " " + f2.get(key).get(0)[1])
.forEach(System.out::println);
}
As can easily be noticed in the code, there are assumptions of valid data an of consistency between the two files. If this doesn't hold, you may need to first run a filter to exclude entries missing in either file:
Stream.concat(f1.keySet().stream(), f2.keySet().stream())
.filter(key -> f1.containsKey(key) && f2.containsKey(key))
.distinct()
...

If you change the order such that the number comes first in both files, you can read both files into a HashMap then create a Set of common keys. Then loop through the set of common keys and grab the associated value from each Hashmap to print:
My solution is verbose but I wrote it that way so that you can see exactly what's happening.
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.io.File;
import java.util.Scanner;
class J {
public static Map<String, String> fileToMap(File file) throws Exception {
// TODO - Make sure the file exists before opening it
// Scans the input file
Scanner scanner = new Scanner(file);
// Create the map
Map<String, String> map = new HashMap<>();
String line;
String name;
String code;
String[] parts = new String[2];
// Scan line by line
while (scanner.hasNextLine()) {
// Get next line
line = scanner.nextLine();
// TODO - Make sure the string has at least 1 space
// Split line by index of first space found
parts = line.split(" ", line.indexOf(' ') - 1);
// Get the class code and string val
code = parts[0];
name = parts[1];
// Insert into map
map.put(code, name);
}
// Close input stream
scanner.close();
// Give the map back
return map;
}
public static Set<String> commonKeys(Map<String, String> nameMap,
Map<String, String> classMap) {
Set<String> commonSet = new HashSet<>();
// Get a set of keys for both maps
Set<String> nameSet = nameMap.keySet();
Set<String> classSet = classMap.keySet();
// Loop through one set
for (String key : nameSet) {
// Make sure the other set has it
if (classSet.contains(key)) {
commonSet.add(key);
}
}
return commonSet;
}
public static Map<String, String> joinByKey(Map<String, String> namesMap,
Map<String, String> classMap,
Set<String> commonKeys) {
Map<String, String> map = new HashMap<String, String>();
// Loop through common keys
for (String key : commonKeys) {
// TODO - check for nulls if get() returns nothing
// Fetch the associated value from each map
map.put(namesMap.get(key), classMap.get(key));
}
return map;
}
public static void main(String[] args) throws Exception {
// Surround in try catch
File names = new File("names.txt");
File classes = new File("classes.txt");
Map<String, String> nameMap = fileToMap(names);
Map<String, String> classMap = fileToMap(classes);
Set<String> commonKeys = commonKeys(nameMap, classMap);
Map<String, String> nameToClass = joinByKey(nameMap, classMap, commonKeys);
System.out.println(nameToClass);
}
}
names.txt
1 James
2 Cody
3 John
5 Max
classes.txt
1 Computer Science
2 Chemistry
3 Physics
4 Biology
Output:
{Cody=Chemistry, James=Computer, John=Physics}
Notes:
I added keys in classes.txt and names.txt that purposely did not match so you see that it does not come up in the output. That is because the key never makes it into the commonKeys set. So, they never get inserted into the joined map.
You can loop through the HashMap if you want my calling map.entrySet()

Related

How to capture the field values in the csv file using bufferedreader

The csv file looks like this
I'm trying to get the field values like name, it is the value after $$NAME$$ (there is a space after the identifier). How do I store the value for each field by using BufferedReader in Java? The fields could be in any line number and not in a fixed place or format, and also throw out an error if there is any special characters or null value is encountered.
int n = 100; // Max lines
String line;
try (BufferedReader br = new BufferedReader(new FileReader(str)))
{
while ((line = br.readLine()) != null && i++ < n)
{
br.readLine();
line = br.readLine();
System.out.println(line);
}
}
Once the values are extracted from the CSV file, I need to store them in a string variable and use it later to insert into the database for each column values
Case 2:And also for the last field $$GROUP$$ CATEGORY the value is "5" in cell 9 to 11 and i need to match that the column CATEGORY in the database has to be 5 stored in a string to be inserted into the database column of the same name.
The regex wont find the exact match when i used line.matches condition
The following code will read only the first 100 lines of the file and extract the values into a list.
java.nio.file.Path path = java.nio.file.Paths.get(str);
try {
java.util.List<String> values = java.nio.file.Files.lines(path)
.limit(100)
.filter(line -> line.matches("\\$\\$[A-Z]+\\$\\$ [0-9A-Z]*$"))
.map(line -> {
String[] words = line.split(" ");
return words.length == 2 ? words[1] : "";
})
.collect(java.util.stream.Collectors.toList());
System.out.println(values);
}
catch (java.io.IOException xIo) {
xIo.printStackTrace();
}
According to the sample file in your question, the above code will create the following list.
[JOHN, CA, SF, XYZ, , 25, CATEGORY, ]
If you want a Map instead of a List where the Map key is the value between the double $ characters and the Map value is the part after the space, then
Function<String, String> keyMapper = line -> {
String[] parts = line.split(" ");
return parts[0].substring(2, parts[0].length() - 2);
};
Function<String, String> valueMapper = line -> {
String[] parts = line.split(" ");
if (parts.length > 1) {
return parts[1];
}
else {
return "";
}
};
Path path = Paths.get(str);
try {
Map<String, String> map = Files.lines(path)
.limit(100)
.filter(line -> line.matches("\\$\\$[A-Z]+\\$\\$ [0-9A-Z]*$"))
.collect(Collectors.toMap(keyMapper, valueMapper));
System.out.println(map);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
This will create the following Map
{GROUP=CATEGORY, WEATHER=, CITY=SF, STATE=CA, TIME=, NAME=JOHN, REGION=XYZ, AGE=25}
You could use regex here to both detect the name line:
int n = 100; // Max lines
String line;
try (BufferedReader br = new BufferedReader(new FileReader(str))) {
while ((line = br.readLine()) != null && i++ < n) {
if (line.matches("\\$\\$NAME\\$\|$.$")) {
System.out.println(line.split(" ")[1]);
}
}
}
I recommend you first split the line by space, then you'll have something like
$$NAME$$, JOHN. Then retrieve the key between the dollar signs.
An example based on your snippet:
int i = 0;
int n = 100; // Max lines
String line;
try (BufferedReader br = new BufferedReader(new FileReader(str))) {
while ((line = br.readLine()) != null && i++ < n) {
String[] splitLine = line.split(" ");
String key = splitLine[0].split("\\$\\$")[1];
String value = splitLine[1];
System.out.printf("Name: %s | Value: %s%n", key, value);
}
}
You could also use a more modern approach using Java 9 Files API and streams, here's an example of that:
public static void main(String[] args) throws IOException, URISyntaxException {
Path filePathFromProjectFolder = Path.of(ClassLoader.getSystemResource("file.csv").toURI());
Map<String, String> csvValues = Files.readAllLines(filePathFromProjectFolder).stream()
.map(line -> line.split(" "))
.collect(Collectors.toMap(line -> getKeyName(line[0]), line -> line[1]));
System.out.println(csvValues);
}
private static String getKeyName(String str) {
return str.split("\\$\\$")[1];
}
You need to extract data from a CSV file according to the format of “fieldname field value”. The code will be rather long if you try to do this in Java.
Try using SPL, the open-source Java package, to get it done. It is easy with only two lines of code:
A
1
=file("data.csv").read#n().select(left(~,2)=="").(right( ,−2).split("")
2
=create(${A1.(~(1)).concat#c()}).record(A1.(~(2)))
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as csv2tbl.splx and invoke it in Java as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call csv2tbl()");
st.execute();
…

How can I unscramble a list of words using a HashMap?

I will be given two files which I need to read into my program. One file will be a list of real words, while the other will be a list of those same words out of order. I need to output the scrambled words in alphabetical order with the real words printed next to them, and I need to do this using a Hashmap. My issue is that I can print out the scrambled word and 1 real word next to it, but in some cases there may be more than one real word for each jumbled word.
for example, my program can do this:
cta cat
stpo post
but I need it to be able to do this:
cta cat
stpo post stop
What changes do I need to make to my code to be able to have more than one dictionary word for each scrambled word? Thank you for your help. My code is below:
import java.io.*;
import java.util.*;
public class Project5
{
public static void main (String[] args) throws Exception
{
BufferedReader dictionaryList = new BufferedReader( new FileReader( args[0] ) );
BufferedReader scrambleList = new BufferedReader( new FileReader( args[1] ) );
HashMap<String, String> dWordMap = new HashMap<String, String>();
while (dictionaryList.ready())
{
String word = dictionaryList.readLine();
dWordMap.put(createKey(word), word);
}
dictionaryList.close();
ArrayList<String> scrambledList = new ArrayList<String>();
while (scrambleList.ready())
{
String scrambledWord = scrambleList.readLine();
scrambledList.add(scrambledWord);
}
scrambleList.close();
Collections.sort(scrambledList);
for (String words : scrambledList)
{
String dictionaryWord = dWordMap.get(createKey(words));
System.out.println(words + " " + dictionaryWord);
}
}
private static String createKey(String word)
{
char[] characterWord = word.toCharArray();
Arrays.sort(characterWord);
return new String(characterWord);
}
}
You need to do several changes. The biggest one is that dWordMap can't hold just one String - it needs to hold the list of words that are found in the scrambled words file.
The next change is being able to manipulate that list. I've added a sample solution which is untested but should give you a good place to start from.
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;
public class Projects {
public static void main (String[] args) throws Exception
{
BufferedReader dictionaryList = new BufferedReader( new FileReader( args[0] ) );
BufferedReader scrambleList = new BufferedReader( new FileReader( args[1] ) );
Map<String, List<String>> dWordMap = new HashMap<>();
while (dictionaryList.ready()) {
String word = dictionaryList.readLine();
dWordMap.put(createKey(word), new ArrayList<>());
}
dictionaryList.close();
while (scrambleList.ready()) {
String scrambledWord = scrambleList.readLine();
String key = createKey(scrambledWord);
List<String> list = dWordMap.get(key);
list.add(scrambledWord);
}
scrambleList.close();
for (Map.Entry<String, List<String>> entry : dWordMap.entrySet()) {
String word = entry.getKey();
List<String> words = entry.getValue();
Collections.sort(words);
System.out.println(concatList(words, " ") + " " + word );
}
}
private static String createKey(String word) {
char[] characterWord = word.toCharArray();
Arrays.sort(characterWord);
return new String(characterWord);
}
private static String concatList(List<String> list, String delimiter) {
StringJoiner joiner = new StringJoiner(delimiter);
list.forEach(joiner::add);
return joiner.toString();
}
}
There a few other changes I would have made - the first is to put the calls to dictionaryList.close(); and scrambleList.close(); in a finally part of a try...catch clause to make sure that the resources are freed in the end no matter what happens. You can also consider using Java 8's Streams to make the code more up to date. I'll be happy to give some more tips if this doesn't fit your needs or you have any more questions. Good luck!
If you want to record the list of dictionary words that are anagrams of each scrambled word then you will need to have a map to a list:
Map<String, List<String>> anagrams = new HashMap<>();
Then, for each scrambled word, you add a list of dictionary words to the map:
anagrams.put(scrambled, allAnagrams(scrambled));
Where allAnagrams would look like:
private List<String> allAnagrams(String scrambled) {
List<String> anagrams = new ArrayList<>();
for (String word: dictionary) {
if (isAnagram(word, scrambled))
anagrams.add(word);
}
Collections.sort(anagrams);
return anagrams;
}
Not that if you have Java 8 and are familiar with streams then this could be:
private List<String> allAnagrams(String scrambled) {
return dictionary.stream()
.filter(word -> isAnagram(scrambled, word))
.sorted()
.collect(Collectors.toList());
}
To improve upon #sprinter's Map<String, List<String>> example:
private final Map<String, List<String>> lookup = new HashMap<>();
public List<String> getList(String word) {
//can also make #computeIfAbsent use an "initializer" for the key
return lookup.computeIfAbsent(word, k -> new ArrayList<>());
}
Then it's simple to interact with:
List<String> words = getList("tspo"); //spot, post, stop, etc...
You can do the unscrambling from there, and could go even further if you wanted to save space and find a way to index the key as a specific list of characters (so that sotp and tpos would do only one lookup).

Comparing two text files in random order with Java

I am trying to compare two text files that are randomized and print out the lines that match in both of the files.
File 1:
Student1
Student2
Student3
Student4
File 2:
Student6
Student1
Student2
I want the output as
Student1
Student2
My code is below.
public static void main(String[] args) throws IOException {
String first = "file1.txt";
String second = "file2.txt";
BufferedReader fBr = new BufferedReader(new FileReader(first));
BufferedReader sBr = new BufferedReader(new FileReader(second));
PrintWriter writer = new PrintWriter("test.txt", "UTF-8");
while ((first = fBr.readLine()) != null) {
String partOne1 = fBr.readLine();
String partTwo1 = sBr.readLine();
while ((second = sBr.readLine()) != null) {
System.out.println(first);
writer.println(first);
break;
}
}
writer.close();
fBr.close();
sBr.close();
It's quite simple=) Try to store all results from first file and compare with all lines from second. It will be like this:
package com.company;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws IOException {
String first = "file1.txt";
String second = "file2.txt";
BufferedReader fBr = new BufferedReader(new FileReader(first));
BufferedReader sBr = new BufferedReader(new FileReader(second));
ArrayList<String> strings = new ArrayList<String>();
while ((first = fBr.readLine()) != null) {
strings.add(first);
}
fBr.close();
while ((second = sBr.readLine()) != null) {
if (strings.contains(second)) {
System.out.println(second);
}
}
sBr.close();
}
}
It's better to use memory when possible, your 'while' inside different while can work too long time and obfuskate logic.
Another alternative is to put both your files in two arraylists and use the arraylist's retainAll() method to get the common files. And do the operations on it like printing or something else.
public static void main(String[] args) throws IOException {
String first = "file1.txt";
String second = "file2.txt";
BufferedReader fBr = new BufferedReader(new FileReader(first));
BufferedReader sBr = new BufferedReader(new FileReader(second));
List<String> firstFile = new ArrayList<>();
List<String> secondFile = new ArrayList<>();
PrintWriter writer = new PrintWriter("test.txt", "UTF-8");
while ((first = fBr.readLine()) != null) {
firstFile.add(first);
}
while ((second = sBr.readLine()) != null) {
secondFile.add(second);
}
List<String> commonFile = new ArrayList<>(firstFile);
commonFile.retainAll(secondFile);
System.out.println(commonFile);
writer.close();
fBr.close();
sBr.close();
}
If you are using Java8 , the following is a terse way of achieving this logic. Please note that this is applicable for Java8 only. It uses some lambda expressions and features available without a lot of boilerplate code. Hope you find it amusing atleast
List<String> file1Lines = Files.readAllLines(Paths.get("C:\\DevelopmentTools\\student-file1.txt"), Charset.defaultCharset());
List<String> file2Lines = Files.readAllLines(Paths.get("C:\\DevelopmentTools\\student-file2.txt"), Charset.defaultCharset());
List<String> matchingStrings = file1Lines.stream().
filter(studentInfo -> file2Lines.contains(studentInfo))
.collect(Collectors.toList());
matchingStrings.forEach(System.out::println);
Prints :
Student1 , Student2
If you want an elegant solution:
Sort both
Compare as sorted lists
First of all, this is very simple. Secondly, sorting is so incredibly well optimized, this will usually be faster than anything manually written, and yield elegant and easy to understand code.
Most of the other solutions here are O(n*m). This approach is O(n log n + m log m) with small constants. You could use a hashmap for lookups, which would theoretically yield O(n + m) but may have too large constants.
Here is sample code it will print matching values and also non matching values in 2 lists
private static void getMatchAndDiff(List<String> list1, List<String> list2) {
List<String> tempList2=new ArrayList<>(list2);
List<String> tempList1=new ArrayList<>(list1);
list1.retainAll(list2);
System.out.println("Matching results: ");
list1.forEach(System.out::println);
System.out.println("Non Matching results: ");
tempList2.removeAll(list1);
tempList1.removeAll(list2);
System.out.println(tempList1+"\n"+tempList2);
}

java class to read csv files instead of text files

The task is to create a java program that reads information from three .csv files and output a list of transcripts, ordered in descending order of aggregate mark, to a file in the current directory called "RankedList.txt". The program should show whether students have passed their year at university and what grade they achieved. The students took two modules, IR101 and IR102. This data is stored in two .csv files, IR101.csv and IR102.csv. Their names and registration numbers are stored in students.csv.
The rules of assessment stipulate the following:
Students must pass both modules in order to proceed to Stage 2. The pass mark for a module is 40.
Students who do not pass both modules will be deemed to have failed.
Students who fail only one of the two modules will be allowed a resit attempt.
Students who fail both modules will be required to repeat the year.
Students who pass both modules will be awarded a class based on their aggregate mark using the following scale:
70 – 100 = 1st
60 – 69.9 = 2.1
50 – 59.9 = 2.2
40 – 49.9 = 3rd
I have been able to complete this task however one problem I have faced is that my code only works for .txt files. If someone could show me how to change my code to work with .csv files I would be most grateful. My program so far is as follows:
package assignment;
import java.io.*;
import java.util.*;
public class StudentsMarks {
public static void main(String[] args) throws FileNotFoundException,IOException {
String currDir = "C:\\Users\\phili_000.Philip.001\\workspace\\ce152\\src\\ass\\StudentsMarks.java";
Scanner sc = new Scanner(new File(currDir+"IRStudents.csv"));
HashMap<Integer, String> students = new HashMap<Integer, String>();
while (sc.hasNext()) {
String line = sc.nextLine();
students.put(sc.nextInt(), sc.next());
String[] parts = line.split(",");
}
sc = new Scanner(new File(currDir+"IR101.csv"));
HashMap<Integer, Double> ir1 = new HashMap<Integer, Double>();
while (sc.hasNext()) {
String line = sc.nextLine();
ir1.put(sc.nextInt(), sc.nextDouble());
String[] parts = line.split(",");
}
sc = new Scanner(new File(currDir+"IR102.csv"));
HashMap<Integer, Double> ir2 = new HashMap<Integer, Double>();
while (sc.hasNext()) {
String line = sc.nextLine();
ir2.put(sc.nextInt(), sc.nextDouble());
String[] parts = line.split(",");
}
File output=new File(currDir+"RankedList.txt");
BufferedWriter b=new BufferedWriter(new FileWriter(output));
Iterator<Integer> ids = students.keySet().iterator();
while (ids.hasNext()) {
Integer id=ids.next();
b.write(id+" "+students.get(id));
b.newLine();
Double marks1=ir1.get(id);
Double marks2=ir2.get(id);
Double aggregate=(marks1+marks2)/2;
b.write("IR101\t "+marks1+"\t IR102\t "+marks2+"\t Aggregate "+aggregate);
b.newLine();
String classStd;
if(aggregate>=70){
classStd="1st";
}else if(aggregate>=60){
classStd="2.1";
}else if(aggregate>=50){
classStd="2.2";
}else if(aggregate>=40){
classStd="3rd";
}else{
classStd="failed";
}
String outcome;
if(marks1<40 && marks2<40){
outcome="Repeat the year";
}else if(marks1<40){
outcome="Resit IR101";
}else if(marks2<40){
outcome="Resit IR102";
}else{
outcome="Proceed to Stage 2";
}
b.write("Class:\t " + classStd + "\t Outcome: " + outcome);
b.newLine();
b.write("----------------------------------------------------");
b.newLine();
}
b.flush();
b.close();
}
}
String csvFile = "path.csv";
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// use comma as separator
String[] parts = line.split(cvsSplitBy);
}
} catch (Exception e) {
e.printStackTrace();
}
when reading a csv you should read the file line by line at the same time you should split the string in the line by using split method then you will
get an array of strings.

Writing back to a csv with Java using super csv

Ive been working on this code for quite sometime and just want to be given the simple heads up if im routing down a dead end. The point where im at now is to mathch identical cells from diffrent .csv files and copy one row into another csv file. The question really is would it be possible to write at specfic lines say for example if the the 2 cells match at row 50 i wish to write back on to row 50. Im assuming that i would maybe extract everything to a hashmap, write it in there then write back to the .csv file? is there a easier way?
for example i have one Csv that has person details, and the other has property details of where the actual person lives, i wish to copy the property details to the person csv, aswell as match them up with the correct person detail. hope this makes sense
public class Old {
public static void main(String [] args) throws IOException
{
List<String[]> cols;
List<String[]> cols1;
int row =0;
int count= 0;
boolean b;
CsvMapReader Reader = new CsvMapReader(new FileReader("file1.csv"), CsvPreference.EXCEL_PREFERENCE);
CsvMapReader Reader2 = new CsvMapReader(new FileReader("file2.csv"), CsvPreference.EXCEL_PREFERENCE);
try {
cols = readFile("file1.csv");
cols1 = readFile("fiel2.csv");
String [] headers = Reader.getCSVHeader(true);
headers = header(cols1,headers
} catch (IOException e) {
e.printStackTrace();
return;
}
for (int j =1; j<cols.size();j++) //1
{
for (int i=1;i<cols1.size();i++){
if (cols.get(j)[0].equals(cols1.get(i)[0]))
{
}
}
}
}
private static List<String[]> readFile(String fileName) throws IOException
{
List<String[]> values = new ArrayList<String[]>();
Scanner s = new Scanner(new File(fileName));
while (s.hasNextLine()) {
String line = s.nextLine();
values.add(line.split(","));
}
return values;
}
public static void csvWriter (String fileName, String [] nameMapping ) throws FileNotFoundException
{
ICsvListWriter writer = new CsvListWriter(new PrintWriter(fileName),CsvPreference.STANDARD_PREFERENCE);
try {
writer.writeHeader(nameMapping);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String[] header(List<String[]> cols1, String[] headers){
List<String> list = new ArrayList<String>();
String [] add;
int count= 0;
for (int i=0;i<headers.length;i++){
list.add(headers[i]);
}
boolean c;
c= true;
while(c) {
add = cols1.get(0);
list.add(add[count]);
if (cols1.get(0)[count].equals(null))// this line is never read errpr
{
c=false;
break;
} else
count ++;
}
String[] array = new String[list.size()];
list.toArray(array);
return array;
}
Just be careful if you read all of the addresses and person details into memory first (as Thomas has suggested) - if you're only dealing with small CSV files then it's fine, but you may run out of memory if you're dealing with larger files.
As an alternative, I've put together an example that reads the addresses in first, then writes the combined person/address details while it reads in the person details.
Just a few things to note:
I've used CsvMapReader and CsvMapWriter because you were - this meant I've had to use a Map containing a Map for storing the addresses. Using CsvBeanReader/CsvBeanWriter would make this a bit more elegant.
The code from your question doesn't actually use Super CSV to read the CSV (you're using Scanner and String.split()). You'll run into issues if your CSV contains commas in the data (which is quite possible with addresses), so it's a lot safer to use Super CSV, which will handle escaped commas for you.
Example:
package example;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import org.supercsv.io.CsvMapReader;
import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapReader;
import org.supercsv.io.ICsvMapWriter;
import org.supercsv.prefs.CsvPreference;
public class CombiningPersonAndAddress {
private static final String PERSON_CSV = "id,firstName,lastName\n"
+ "1,philip,fry\n2,amy,wong\n3,hubert,farnsworth";
private static final String ADDRESS_CSV = "personId,address,country\n"
+ "1,address 1,USA\n2,address 2,UK\n3,address 3,AUS";
private static final String[] COMBINED_HEADER = new String[] { "id",
"firstName", "lastName", "address", "country" };
public static void main(String[] args) throws Exception {
ICsvMapReader personReader = null;
ICsvMapReader addressReader = null;
ICsvMapWriter combinedWriter = null;
final StringWriter output = new StringWriter();
try {
// set up the readers/writer
personReader = new CsvMapReader(new StringReader(PERSON_CSV),
CsvPreference.STANDARD_PREFERENCE);
addressReader = new CsvMapReader(new StringReader(ADDRESS_CSV),
CsvPreference.STANDARD_PREFERENCE);
combinedWriter = new CsvMapWriter(output,
CsvPreference.STANDARD_PREFERENCE);
// map of personId -> address (inner map is address details)
final Map<String, Map<String, String>> addresses =
new HashMap<String, Map<String, String>>();
// read in all of the addresses
Map<String, String> address;
final String[] addressHeader = addressReader.getCSVHeader(true);
while ((address = addressReader.read(addressHeader)) != null) {
final String personId = address.get("personId");
addresses.put(personId, address);
}
// write the header
combinedWriter.writeHeader(COMBINED_HEADER);
// read each person
Map<String, String> person;
final String[] personHeader = personReader.getCSVHeader(true);
while ((person = personReader.read(personHeader)) != null) {
// copy address details to person if they exist
final String personId = person.get("id");
final Map<String, String> personAddress = addresses.get(personId);
if (personAddress != null) {
person.putAll(personAddress);
}
// write the combined details
combinedWriter.write(person, COMBINED_HEADER);
}
} finally {
personReader.close();
addressReader.close();
combinedWriter.close();
}
// print the output
System.out.println(output);
}
}
Output:
id,firstName,lastName,address,country
1,philip,fry,address 1,USA
2,amy,wong,address 2,UK
3,hubert,farnsworth,address 3,AUS
From your comment, it seems like you have the following situation:
File 1 contains persons
File 2 contains addresses
You then want to match persons and addresses by some key ( one or more fields) and write the combination back to a CSV file.
Thus the simplest approach might be something like this:
//use a LinkedHashMap to preserve the order of the persons as found in file 1
Map<PersonKey, String[]> persons = new LinkedHashMap<>();
//fill in the persons from file 1 here
Map<PersonKey, String[]> addresses = new HashMap<>();
//fill in the addresses from file 2 here
List<String[]> outputLines = new ArrayList<>(persons.size());
for( Map.Entry<PersonKey, String[]> personEntry: persons.entrySet() ) {
String[] person = personEntry.getValue();
String[] address = addresses.get( personEntry.getKey() );
//merge the two arrays and put them into outputLines
}
//write outputLines to a file
Note that PersonKey might just be a String or a wrapper object ( Integer etc.) if you can match persons and addresses by one field. If you have more fields you might need a custom PersonKey object with equals() and hashCode() properly overridden.

Categories

Resources