I am trying to only run nextLine() at the end of every run of the loop so that it starts the loop with the new line each iteration through, but at the end of the last run, i dont want it to run the nextLine() because it skips the data i need for the rest of my program. how do i fix this?
String hasInt = fileIn.nextLine();
while(Character.isDigit(hasInt.charAt(0)))
{
data = hasInt.split(",");
info = Integer.parseInt(data[0]);
def = data[1];
case = data[2];
free = data[3];
Case newCase = new Case(info, def, case, free);
miner.addCase(newCase);
hasInt = fileIn.nextLine();
}
Well combining it all into that for loop seemed to work, that got me all the way through the loop, and seemed to work, but now at the start of the method it got stuck in an infinite loop
while(fileIn.hasNextLine())
{
if(fileIn.hasNext("[A-Za-z]+"))
{
do {
String hasInt = fileIn.nextLine();
if (!Character.isDigit(hasInt.charAt(0)) {
break;
}
// rest of your code here
} while(true);
You could try merging the statements into a for loop:
for(
String hasInt = fileIn.nextLine();
Character.isDigit(hasInt.charAt(0));
hasInt = fileIn.nextLine()
) {
data = hasInt.split(",");
info = Integer.parseInt(data[0]);
def = data[1];
case = data[2];
free = data[3];
Case newCase = new Case(info, def, case, free);
miner.addCase(newCase);
}
I am not sure how clean it would be but; it seems that you could use hasInt after the while loop to get the value that you do not want to skip.
Hi you will not loss the data since the data you read last is in the hasInt variable. So use it after the while loop.
String hasInt = fileIn.nextLine();
while(Character.isDigit(hasInt.charAt(0)))
{
data = hasInt.split(",");
info = Integer.parseInt(data[0]);
def = data[1];
case = data[2];
free = data[3];
Case newCase = new Case(info, def, case, free);
miner.addCase(newCase);
hasInt = fileIn.nextLine();
}
//use the hasInt variable here to get the last read data...
Related
Hi.
I'm making an app that receives data from bluetooth by using stringbuilder
And makes it slice for using another activity.
The image shows what i want to make.
Q1. What should i use c->d, d->e ?
Q2. There will be a lot of data, I want to know the way to simplify this sequence
******************** edited ********************
I have practiced by adding value to Arraylist.
But in String Array, there is no .get(), so i couldn't access to element's length.
public static ArrayList<String> randomValue = new ArrayList<>();
public static int iDistance=0, xIAngle=0, yIAngle=0, zIAngle=0;
public static String distance, xAngle, yAngle, zAngle;
randomValue.add("12345090080070");
randomValue.add("15640080085071");
randomValue.add("16542070084074");
randomValue.add("12645080087078");
randomValue.add("21345084081060");
randomValue.add("14785078075065");
randomValue.add("13155079077077");
randomValue.add("14623080078078");
randomValue.add("14918086080078");
randomValue.add("15684085082080");
for (int i=0; i<randomValue.size(); i++){
String a = randomValue.get(i);
String distance = a.substring(0,5);
String xAngle = a.substring(5,8);
String yAngle = a.substring(8,11);
String zAngle = a.substring(11,14);
//String to int
iDistance = Integer.parseInt(distance);
xIAngle = Integer.parseInt(xAngle);
yIAngle = Integer.parseInt(yAngle);
zIAngle = Integer.parseInt(zAngle);
}
It seems like you are just stuck on finding the equivalent of get for a string array. To access an element in an array, the syntax is array[I], so if you were using a string array, this line:
String a = randomValue.get(i);
would have been:
String a = randomValue[i];
The code for your sequence of transformations can be shortened with Streams:
// this is the sequence of transformation starting with the sting builder "a"
List<String> randomValueWithLength14 =
Arrays.stream(a.toString().split(";")).filter(x -> x.length() == 14)
.collect(Collectors.toList());
// this is the for loop shown in your code
for (int i=0; i<randomValueWithLength14.size(); i++){
String s = randomValueWithLength14.get(i);
String distance = a.substring(0,5);
String xAngle = s.substring(5,8);
String yAngle = s.substring(8,11);
String zAngle = s.substring(11,14);
//String to int
iDistance = Integer.parseInt(distance);
xIAngle = Integer.parseInt(xAngle);
yIAngle = Integer.parseInt(yAngle);
zIAngle = Integer.parseInt(zAngle);
}
This maybe simple but java isn’t really my thing but I'm working with a java API.
I need to parse a csv file and use the values as strings.
CSV file:
Mac,device,level ,key number,key function ,name,number,prim
01:1A:E8:84:9D:27,0,0,1,31,line,441865945218,TRUE
01:1A:E8:84:9D:27,0,0,2,51,dss,441865985452,FALSE
each row need to be read seprately so something like.
Read first row of csv
Assign values to strings (e.g. mac = 01:1A:E8:84:9D:27 device = 0 and so on)
Run "code" using these strings
Read second row of csv
So on till end of csv.
Thanks
I have tried csvreader but I'm not able to use the strings outside of the while function and it does not read line by line.
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
while (phones.readRecord()){
String deviceID = phones.get("Mac");
String device = phones.get("device");
String level = phones.get("level");
String keynumber = phones.get("key number");
String keyfunction = phones.get("key Function");
String label = phones.get("name");
String e164 = phones.get("number");
String prim = phones.get("prim");
}
As you are new to Java, whatever you are doing, looks like it reads the file line by line. But as you are defining the Strings in while loop, you won't be able to access it outside.
If you want to read all lines and store in Strings, you should probably take array for all of them and define them outside the while loop, add values in the loop and then you'll be able to use it.
Or just create a Phone class:
public class Phone{
String deviceId;
String device;
......etc...
//setters and getters
}
And take an array of it outside while. Something like this:
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
List<Phone> phonesArr=new ArrayList<Phone>();
while (phones.readRecord())
{
Phone phone=new Phone();
phone.setDeviceId(phones.get("Mac"));
phone.setDevice(phones.get("device"));
.....
phones.add(phone);
}
// array phones will be accessible here
Hope that helps!
You have to declare the Strings outside of the loop. Otherwise the String variables would be loop scoped.
CsvReader phones = new CsvReader("dls.csv");
phones.readHeaders();
String deviceID;
String device;
String level;
String keynumber;
String keyfunction;
String label;
String e164;
String prim;
while (phones.readRecord()){
deviceID = phones.get("Mac");
device = phones.get("device");
level = phones.get("level");
keynumber = phones.get("key number");
keyfunction = phones.get("key Function");
label = phones.get("name");
e164 = phones.get("number");
prim = phones.get("prim");
}
See:
Scopes tutorial
Javadoc: Variables
In the end I just called the funtion from the while loop.
while (phones.readRecord()) {
deviceID = phones.get("Mac");
Device = phones.get("device");
Level = phones.get("level");
Keynumber = phones.get("key number");
Keyfunction = phones.get("key function");
Label = phones.get("name");
E164 = phones.get("number");
Prim = phones.get("prim");
tools connect = new tools();
connect.connect();
connect.setkeys(deviceID,Device,Level,Label,Keynumber,Keyfunction,E164,Prim);
//System.out.println(Prim);
}
phones.close();
Search by id method:
public class ClientsDetailsList {
public ArrayList <ClientDetails> aListOfClientDetails;
public ClientDetails getClientDetails(String givenID) {
boolean found = false;
int index = 0;
for(;index<aListOfClientDetails.size();index++){
if((aListOfClientDetails.get(index).ClientID.equals(givenID)))
found = true;
}
if(found)
return aListOfClientDetails.get(index);
else return null;
}
}
aListOfClientDetails List format It reads a file and creates a list of ClientDetails.
[IC-x00042W Ms LQ Bethea 205, Willis Road Bolton BO5 1DQ 2000000007 2000100037 2006200319,
IC-x00033D Mr R Bowie 119, Thatcher Way Glasgow GL9 5SX 2006000016 2003100008 2005300001,
IC-x00013A MS GRV Blackwell 209, Drunk Road Hawick HK8 1MY 2006000009 2004100014 2003200304,
IC-x00018O Ms NAP Wallis 244, Grubb Lane Durham DU4 4ZX 2000000006 2003100012 2006200305]
One line is an object of the list. With the method above I try to return an object of the list found by ID (e.g. first token IC-x00042W). However when I run this in my main method it returns Only the first object.(IC-x00042W/Ms/LQ/Bethea/205, Willis Road/Bolton/BO5.....)
If I search by id of another object it returns null.
Source of ClientDetailsList:
The txt file has the following data:
IC-x00042W/Ms/LQ/Bethea/205, Willis Road/Bolton/BO5 1DQ/2000000007/2000100037/2006200319#
IC-x00033D/Mr/R/Bowie/119, Thatcher Way/Glasgow/GL9 5SX/2006000016/2003100008/2005300001#
IC-x00013A/MS/GRV/Blackwell/209, Drunk Road/Hawick/HK8 1MY/2006000009/2004100014/2003200304#
IC-x00018O/Ms/NAP/Wallis/244, Grubb Lane/Durham/DU4 4ZX/2000000006/2003100012/2006200305#
IC-x00037N/Miss/DOD/Burke/272, Ambrose Lane/Cambridge/CB2 2XD/2005000003/2001100020#
IC-x00039A/Dr/X/Salter/285, Bannister Road/Sea Palling/SP2 6GW/2000000002/2005100029/2005200306#
IC-x00011I/MR/R/Reece/104, Bannister Lane/Cromer/CR0 6LD/2005000012/2003100001/2001200300#
IC-x00025V/Mr/P/Abbott/163, Drunk Lane/Hunstanton/HU1 1UR/2003000029/2004100017#
IC-x00008L/Dr/P/Runyon/150, Tick Tock Way/Swindon/SW8 4OJ/2004000005/2006100005/2001200316#
IC-x00028F/MR/X/Watt/267, Malton Road/Cambridge/CB4 1PQ/2004100016/2004200312#
IC-x00031X/Mr/S/Lorenz/276, Tick Tock Way/London/LN9 7ID/2005000023/2005100007#
IC-x00020C/Mr/LNV/Mcmillan/44, Drunk Street/London/LN6 1RG/2001000019#
IC-x00015H/Mr/TQZ/Dubose/201, Drunk Road/London/LN4 5RA/2003000026/2006100028/2000200307#
//Creates ClientsDetailsList from source file
public static ClientsDetailsList readFile(File inputFile) throws IOException{
ArrayList <String> clientData = new ArrayList<String>();
ArrayList <ClientDetails> cdList = new ArrayList<>();
ArrayList <PolicyList> arrayofPolsLists = new ArrayList<>();
//Lists of ClientDetails fields
ArrayList <Name> clientName = new ArrayList<>();
ArrayList <String> clientID = new ArrayList<String>();
ArrayList <Address> clientAddress = new ArrayList<>();
// Lists of Name class fields
ArrayList <String> clientTitle = new ArrayList<String>();
ArrayList <String> clientInitials = new ArrayList<String>();
ArrayList <String> clientSurname = new ArrayList<String>();
//Lists of Address class fields
ArrayList <String> clientStreet = new ArrayList<String>();
ArrayList <String> clientCity = new ArrayList<String>();
ArrayList <String> clientPostCode = new ArrayList<String>();
ArrayList <ArrayList <Policy>> list = new ArrayList<ArrayList<Policy>>();
Scanner fileScan = new Scanner(inputFile);
fileScan.useDelimiter("#");
int i =0;
//Reading the file
while(fileScan.hasNext()){
clientData.add(fileScan.next());
Scanner cdScan = new Scanner(clientData.get(i));
cdScan.useDelimiter("/");
ArrayList <String> tokens = new ArrayList<String>();
ArrayList <Policy> clientPolicyNo = new ArrayList<>();
while(cdScan.hasNext()){
tokens.add(cdScan.next());
}
clientID.add(tokens.get(0));
clientTitle.add(tokens.get(1));
clientInitials.add(tokens.get(2));
clientSurname.add(tokens.get(3));
clientStreet.add(tokens.get(4));
clientCity.add(tokens.get(5));
clientPostCode.add(tokens.get(6));
boolean whileController = true;
while(whileController){
clientPolicyNo.add(new Policy(tokens.get(7)));
switch(tokens.size()){
case 9 : clientPolicyNo.add(new Policy(tokens.get(8)));
break;
case 10: clientPolicyNo.add(new Policy(tokens.get(8)));
clientPolicyNo.add(new Policy(tokens.get(9)));
break;
case 11: clientPolicyNo.add(new Policy(tokens.get(8)));
clientPolicyNo.add(new Policy(tokens.get(9)));
clientPolicyNo.add(new Policy(tokens.get(10)));
break;
}
whileController=false;
}
list.add(clientPolicyNo);
i++;
}
//Adding policy lists
for(int j =0; j<clientID.size();j++){
arrayofPolsLists.add(new PolicyList());
arrayofPolsLists.get(j).aListOfPolicies=list.get(j);
}
//Creating Name objects
for(int j =0;j<clientID.size();j++){
clientName.add(new Name());
clientName.get(j).Title = clientTitle.get(j);
clientName.get(j).Initials = clientInitials.get(j);
clientName.get(j).Surname = clientSurname.get(j);
}
//Creating Address objects
for(int j =0;j<clientID.size();j++){
clientAddress.add(new Address());
clientAddress.get(j).street = clientStreet.get(j);
clientAddress.get(j).city = clientCity.get(j);
clientAddress.get(j).postcode = clientPostCode.get(j);
}
//Creating ClientDetails
for(int j =0;j<clientID.size();j++){
cdList.add(new ClientDetails());
cdList.get(j).ClientID = clientID.get(j);
cdList.get(j).fullName = clientName.get(j);
cdList.get(j).fullAddress = clientAddress.get(j);
cdList.get(j).clientsPolicies = arrayofPolsLists.get(j);
}
//Creating a ClientDetailsList object
ClientsDetailsList ClientDetList = new ClientsDetailsList();
ClientDetList.aListOfClientDetails = cdList;
return ClientDetList;
}
ClientDetails class has 4 fields:
public String ClientID;
public Name fullName;
public Address fullAddress;
public PolicyList clientsPolicies;
Main method
File clientsFile = new File("ClientDetailsInput");
InputData e = new InputData();
ClientsDetailsList testList = new ClientsDetailsList();
testList = e.readFile(clientsFile);
System.out.println(testList.getClientDetails("IC-x00013A"));
Put a break after found = true;, for example...
public ClientDetails getClientDetails(String givenID) {
boolean found = false;
int index = 0;
for(;index<aListOfClientDetails.size();index++){
if((aListOfClientDetails.get(index).ClientID.equals(givenID))) {
found = true;
break;
}
}
if(found)
return aListOfClientDetails.get(index);
else return null;
}
Or you could simplify it further, by doing away with the need for the index at all, for example
public ClientDetails getClientDetails(String givenID) {
boolean found = false;
int index = 0;
ClientDetails details = null;
for (ClientDetails check : aListOfClientDetails) {
if(check.ClientID.equals(givenID)) {
details = check;
break;
}
}
return details;
}
Updated
After actually been able to read the data, I added
String check = aListOfClientDetails.get(index).ClientID;
System.out.println(givenID + " = " + check);
if ((check.equals(givenID))) {
to the search list and it printed...
IC-x00013A = IC-x00042W
IC-x00013A =
IC-x00033D
IC-x00013A =
IC-x00013A
IC-x00013A =
IC-x00018O
IC-x00013A =
IC-x00037N
IC-x00013A =
IC-x00039A
IC-x00013A =
IC-x00011I
IC-x00013A =
IC-x00025V
IC-x00013A =
IC-x00008L
IC-x00013A =
IC-x00028F
IC-x00013A =
IC-x00031X
IC-x00013A =
IC-x00020C
IC-x00013A =
IC-x00015H
...which freaked me out, until I realised that the ID's were prefixed with a new line character...!
So what I did was add trim to each result from the tokens in the read method...
clientID.add(tokens.get(0).trim());
(I did it for each line, just haven't shown), which then lead to
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 13, Size: 13
at java.util.ArrayList.rangeCheck(ArrayList.java:638)
at java.util.ArrayList.get(ArrayList.java:414)
at testsearch.TestSearch$ClientsDetailsList.getClientDetails(TestSearch.java:47)
at testsearch.TestSearch.main(TestSearch.java:23)
Which is what I expected should happen in your search method...
If we have a closer look at the search loop...
for(;index<aListOfClientDetails.size();index++){
if((aListOfClientDetails.get(index).ClientID.equals(givenID)))
found = true;
}
You should be able to see, that regardless of the state of found, the index will ALWAYS be equal to aListOfClientDetails.size() at the end of the loop, as there is no other exit condition to the loop that takes found into consideration...
Which takes me back to my original suggestions...
Never discount the power of a simple System.out.println statement to check your sanity and a good debugger...
Debugging would have helped i guess.
At the end you are returning
return aListOfClientDetails.get(i);
But you should get index "index" instead of "i" that was never initiated as far as i see.
So replace that with
return aListOfClientDetails.get(index);
And of course dont forget to leave the loop when you find something so index stays the right index.
Or just return the object right after you found it instead of setting found to true.
And last but not least: I dont know ClienID so I cant tell from here but if it does not implement the equals function the you actually will not get it work the way you want. So check what it does and perhaps override it.
Setting the Scanner's delimiter to '#' or '/' causes the line separators \n (whatever it is on your system) to remain in the data. So, some next() method call will eventually produce a String value with a leading \n, which is bound to happen for all IDs from the second one up, if the line structure is aligned with the '#' signs.
The code you have for parsing is extremely complex. I'd advocate to read lines (\n-delimited) and handle one line at a time, using
String[] tokens = line.split( "/" );
and assigning the strings to the destination fields of one object. Avoid the many lists - this only confuses matters.
This is my code:
String bericht = "";
while (cur.moveToNext()) {
if (cur.getString(cur.getColumnIndex("address")).equals("SAH")) {
bericht += cur.getString(cur.getColumnIndex("body"));
adress = getadress(bericht); //basically cutting a part out
datum = getdatum(bericht); //same
afspraken[x][0] = datum;
afspraken[x][1] = adress;
x++;
}
cur.moveToNext();
bericht = "";
}
It works without the bericht = ""; at the end but I want to reset the string with every loop!
I tried:
String bericht;
bericht = cur.getString(cur.getColumnIndex("body"));
Error message:
E/AndroidRuntime(3171): java.lang.StringIndexOutOfBoundsException: length=0; index=2
It seems you reset the string in every iteration anyway. You can just declare bericht inside iteration as you don't need it outside.
while (cur.moveToNext()) {
if (cur.getString(cur.getColumnIndex("address")).equals("SAH")) {
String bericht = cur.getString(cur.getColumnIndex("body"));
adress = getadress(bericht); //basically cutting a part out
datum = getdatum(bericht); //same
afspraken[x][0] = datum;
afspraken[x][1] = adress;
x++;
}
cur.moveToNext();
}
Also, it seems that the heart of the problem lies in getadress(bericht); or getdatum(bericht);. Check how you process your string there.
A bit of a guess here since the exception doesn't occur in the code parts posted, but this might help:
String bericht = "";
while (cur.moveToNext()) {
if (cur.getString(cur.getColumnIndex("address")).equals("SAH")) {
bericht = cur.getString(cur.getColumnIndex("body"));
if (bericht != null && !bericht.trim().isEmpty()) {
adress = getadress(bericht); //basically cutting a part out
datum = getdatum(bericht); //same
afspraken[x][0] = datum;
afspraken[x][1] = adress;
x++;
}
}
cur.moveToNext();
}
What's changed is that we check if the String we put in bericht is something we can reasonably expect to work when calling getadress(...) and getdatum(...) with it. You may want to check even more (minimum length of X for example), but since I can't see what the methods do I can't really tell you what that would be.
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