I need to use printf to print data from a text file (the HashMap map is already populated, the Account values aren't null, everything is fine). But how do I use regex to not only maintain the even spacing of 20 spaces between my columns, but also round the last column, "Balance," to only 1 decimal point? I've looked at similar threads, but those formatting rules either threw errors or just had no effect. I tried using "%20s %20s %20s %20s.1f \n" for the first argument, but I ended up with this:
ID First Name Last Name Balance.1f
107H Alessandro Good 6058.14
110K Kolby Cain 8628.4
100A Matias Kane 290.99
103D Macie House 631.12
108I Allan Turner 914.89
106G Nancy Avery 5201.38
105F Semaj Olsen 344.63
109J Wilson Hudson 771.65
102C Alana Farmer 2004.5
101B Johnathan Burgess 457.35
104E Andres Rivers 3487.87
The total balance in all the accounts is: $28790.92
So it apparently only worked for a few of the data points?
Here's my code:
public void printData() {
System.out.printf("%20s %20s %20s %20s%.1f \n", "ID", "First Name", "Last Name", "Balance");
for(Account a : map.keySet()) {
// could do a.getID(), but rather get value from ArrayList
ArrayList<String> myList = map.get(a); // retrieve the VALUE (ArrayList) using the key (Account a)
for(String s : myList) {
System.out.printf("%20s", s);
}
System.out.println();
}
}
In your code, the decimals on each row under the column "balance" are simply being printed as the strings they are. The %.1f in the first line is only being used for the header row as formatting for a 5th argument it isn't receiving, and is not being applied to each following row.
Try this:
System.out.printf("%20s %20s %20s %20s\n", "ID", "First Name", "Last Name", "Balance");
for(Account a : map.keySet()) {
ArrayList<String> myList = map.get(a);
//print the first 3 columns as strings
for(int i = 0; i < myList.size()-1; i++) {
String s = myList.get(i);
System.out.printf("%20s", s);
}
//print the last column as a decimal rounded to 1 place after the decimal
float balance = Float.parseFloat(myList.get(myList.size()-1));
System.out.printf("%20s%.1f", "", balance);
System.out.println();
}
Related
I need split String to array. For exapmle i have string str = "apple fruits money Pacific Ocean".
and I try split to array like this:
String []arr = str.split(" ");
But I need the Pacific Ocean to register in one cell of the array. I can't change the separator, because i get data in this form ("apple fruits money Pacific Ocean").
If we admit that multiple consecutive capitalized words need to be considered as a single word, then you can do:
String []arr = str.split("\\s");
then
`String str = "apple fruits money Pacific Ocean";
String[] arr = str.split("\\s");
String[] finalArr = new String[arr.length];
int i = 0;
for (String word : arr) {
// capitalized
if (Character.isUpperCase(word.charAt(0))) {
// check if previous is capitalized
if (Character.isUpperCase(finalArr[i - 1].charAt(0))) {
finalArr[i - 1] = finalArr[i - 1] + word + " ";
} else {
finalArr[i] = word + " ";
}
} else {
finalArr[i] = word;
}
i++;
}
for (String s : finalArr) {
System.out.println(s);
}
}
}`
will result in:
apple
fruits
money
Pacific Ocean
null
You'll need to filter the nulls though and add some checks (if i-1 exists at all).
You need to change the separator as Elliott Frisch stated in his comment. You're not going to be able to determine whether or not a set of words need to stay together if they contain a space. If your word list were separated by another character (such as a comma) then the problem becomes much easier to solve.
String input = "apples,fruits,money,Pacific Ocean";
String[] arr = input.split(",");
Now your array contains each of the words in input.
The problem as described in the question and comments has no solution.
Consider this:
"banana red apple green apple"
This can be split like this:
["banana", "red", "apple", "green", "apple"]
or like this
["banana", "red apple", "green apple"]
Without semantic / contextual analysis it is impossible to know which is more likely to be correct. And it is impossible to know for sure what the (human) user actually meant.
I can't change the separator, because i get data in this form ("apple fruits money Pacific Ocean").
You need to redesign the form or the input syntax so that your software doesn't need to perform this task. There is no other way ... to always get the correct answer.
Think of it this way. Suppose someone gave you a sequence of words in a foreign language on a piece of paper, and asked you to split them correctly. How would you (a human) solve the problem, assuming that you didn't understand the language, and hadn't been given a dictionary or a set of rules? This is equivalent to the task you are setting the computer ...
This way it's not possible. If the string was joined earlier, try using a character other than space. Maybe the pipe | might be an option.
I have a CSV file with a non standardized content, it goes something like this:
John, 001
01/01/2015, hamburger
02/01/2015, pizza
03/01/2015, ice cream
Mary, 002
01/01/2015, hamburger
02/01/2015, pizza
John, 003
04/01/2015, chocolate
Now, what I'm trying to do is to write a logic in java to separate them.I would like "John, 001" as the header and to put all the rows under John, before Mary to be John's.
Will this be possible? Or should I just do it manually?
Edit:
For the input, even though it is not standardized, a noticeable pattern is that the row that do not have names will always starts with a date.
My output goal would be a java object, where I can store it in the database eventually in the format below.
Name, hamburger, pizza, ice cream, chocolate
John, 01/01/2015, 02/01/2015, 03/01/2015, NA
Mary, 01/01/2015, 02/01/2015, NA, NA
John, NA, NA, NA, 04/01/2015
You could just read the file into a list
List<String> lines = Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8);
Afterwards iterate over the list and split them for wanted delimiters (",").
Now you could just use if-else or switch blocks to check for specific entries.
List<DataObject> objects = new ArrayList<>();
DataObject dataObject = null;
for(String s : lines) {
String [] splitLine = s.split(",");
if(splitLine[0].matches("(\d{2}\/){2}\d{4}")) {
// We found a data
if(dataObject != null && splitLine.length == 2) {
String date = splitLine[0];
String dish = splitLine[1];
dataObject.add(date, dish);
} else {
// Handle error
}
} else if(splitLine.length == 2) {
// We can create a new data object
if(dataObject != null) {
objects.add(dataObject);
}
String name = splitLine[0];
String id = splitLine[1];
dataObject = new DataObject(name, id);
} else {
// Handle error
}
}
Now you can sort them into your specific categories.
Edit: Changed the loop and added a regex (which may not be optimal) for matching the date strings and using them to decide whether to add them to the last data object.
The DataObject class can contain data structures holding the dates/dishes. When the CSV is parsed you can iterate over the objects List and do whatever you want. I hope this answer helps :)
If I have correctly understood, the specs are :
input is text, one record per line (fields are comma delimited)
2 kinds of records :
headers consisting of a name and a number (number is ignored)
actual records consisting of a date and a meal
output should contain :
one header containing the constant Name, and the meals in order of occurence
on record per name consisting with the name and the dates corresponding to the meals - an absent field will have NA constant string
we assume that we will never get for a name the same date for different input records.
The algorithm is in pseudo code :
Data structures :
one list of struct< string name, hash< int meal index, date> > for the names : base
one list of strings for the meals : meals
Code :
name = null
iname = -1
Loop per input lines {
if first field is date {
if name == null {
throw Exception("incorrect structure");
}
meal = second field
look for index of meal in meals
if not found {
index = len(meals);
add meal at end of list meals
}
base[iname].hash[index] = date
}
else {
name = first field
iname += 1
add a new struc { name, empty hash } at end of list base
}
}
close input file
open output file
// headers
print "names"
for meal in meals {
print ",", meal
}
print newline
for (i=0; i<=iname; i++) {
print base[i].name
for meal in meals {
look for meal in base[i].hash.keys
if found {
print ",", base[i].hash[meal]
}
else {
print ",NA"
}
}
print newline
}
close output file
Just code it in correct Java and come back here if you have any problem.
Use uniVocity-parsers to handle this for you. It comes with a master-detail row processor.
// 1st, Create a RowProcessor to process all "detail" elements (dates/ingredients)
ObjectRowListProcessor detailProcessor = new ObjectRowListProcessor();
// 2nd, Create MasterDetailProcessor to identify whether or not a row is the master row (first value of the row is a name, second is an integer).
MasterDetailListProcessor masterRowProcessor = new MasterDetailListProcessor(RowPlacement.TOP, detailProcessor) {
#Override
protected boolean isMasterRecord(String[] row, ParsingContext context) {
try{
//tries to convert the second value of the row to an Integer.
Integer.parseInt(String.valueOf(row[1]));
return true;
} catch(NumberFormatException ex){
return false;
}
}
};
CsvParserSettings parserSettings = new CsvParserSettings();
// Set the RowProcessor to the masterRowProcessor.
parserSettings.setRowProcessor(masterRowProcessor);
CsvParser parser = new CsvParser(parserSettings);
parser.parse(new FileReader(yourFile));
// Here we get the MasterDetailRecord elements.
List<MasterDetailRecord> rows = masterRowProcessor.getRecords();
// Each master record has one master row and multiple detail rows.
MasterDetailRecord masterRecord = rows.get(0);
Object[] masterRow = masterRecord.getMasterRow();
List<Object[]> detailRows = masterRecord.getDetailRows();
Disclosure: I am the author of this library. It's open-source and free (Apache V2.0 license).
i have 3 paragraphs and i try to get one sentence per paragraph. but, the sentences taken randomly.
beside that, it performed a total of 2 times iteration.
example :
String sentences = "i love u. i like u. i get money. \nOther side.
A new car. white paint. \nSomething else. i see the sky.
i took a money yesterday. ";
there are 3 paragraphs and 9 sentences. I want to get output like this :
output :
(P : Paragraph, S = Sentence)
First iteration :
P0S1 : i like you
P1S0 : Other side
P2S1 : i see the sky
second iteration :
P0S2 : i get money
P1S2 : white paint
P2S0 : Something else
the sentence above is get by randomly
i have tried to pair the key and its sentence, but don't how to get the sentence randomly
my code :
Map<String,String> mapIndeksKeyAndSentence = new LinkedHashMap<String,String>();
String sentences = "i love u. i like u. i get money. \nOther side.
A new car. white paint. \nSomething else. i see the sky.
i took a money yesterday. ";
String [] arrSentence = sentence.split("\n");
for(int i=0; i<arrSentence.length; i++){
String[] arrSentenceByDot = arrSentence[i].split("\\. ");
for(int j=0; j<arrSentenceByDot.length; j++){
mapIndeksKeyAndSentence.put(i+""+j, arrSentenceByDot[j]);
}
}
and the ouput of mapIndeksKeyAndSentence is ::
the index : 00 //means = paragraph one, sentence one
the sentence : i love you
.
.
.
etc . .
so, how do i get the sentence randomly with two iterations?.. help, please.
You could make a list of all possible indices and suffle it using Collections.suffle(...). Something like this:
import java.util.Collections;
...
...
List<Integer> indices = new ArrayList<>(arrSentenceByDot.length);
for(int j=0; j<arrSentenceByDot.length; j++){
indices.add(j);
}
Collections.shuffle(indices);
for(int j=0; j<indices.size(); j++){
int index = indices.get(j);
mapIndeksKeyAndSentence.put(i+""+index, arrSentenceByDot[index]);
}
try:
public static void main(String[] args) {
String sentences = "i love u. i like u. i get money. \nOther side. A new car. white paint. \nSomething else. i see the sky. i took a money yesterday. ";
List<String[]> paragraphs = new ArrayList<String[]>();
for(String s : sentences.split("\n"))
paragraphs.add(s.split("\\. "));
int i = 0;
for(String[] ss : paragraphs)
System.out.println("P" + i++ + "S" + getRandom(ss));
}
public static String getRandom(String[] s) {
int i = (int) (Math.random() * s.length);
return s[i];
}
I'm printing data line by line and want it to be organized like a table.
I initially used firstName + ", " + lastName + "\t" + phoneNumber.
But for some of the larger names, the phone number gets pushed out of alignment
I'm trying to use String.format() to achieve this effect. Can anyone tell me the format syntax to use?
I tried String.format("%s, %s, %20s", firstName, lastName, phoneNumber), but that's not what I want. I want it to look like this:
John, Smith 123456789
Bob, Madison 123456789
Charles, Richards 123456789
Edit:
These answers seem to work for System.out.println(). But I need it to work for a JTextArea. I'm using textArea.setText()
Worked it out. JTextArea doesn't use monospaced fonts by default. I used setFont() to change that, and now it works like a charm. Thank you all for the solutions.
consider using a negative number for your length specifier: %-20s. For example:
public static void main(String[] args) {
String[] firstNames = {"Pete", "Jon", "Fred"};
String[] lastNames = {"Klein", "Jones", "Flinstone"};
String phoneNumber = "555-123-4567";
for (int i = 0; i < firstNames.length; i++) {
String foo = String.format("%-20s %s", lastNames[i] + ", " +
firstNames[i], phoneNumber);
System.out.println(foo);
}
}
returns
Klein, Pete 555-123-4567
Jones, Jon 555-123-4567
Flinstone, Fred 555-123-4567
Try putting the width into second placeholder with - sign for right padding as:
String.format("%s, %-20s %s", firstName, lastName, phoneNumber)
This will give the specified width to the second argument(last name) with right padding and phone number will start after the specified width string only.
EDIT: Demo:
String firstName = "John";
String lastName = "Smith";
String phoneNumber = "1234456677";
System.out.println(String.format("%s, %-20s %s",firstName, lastName, phoneNumber));
prints:
John, Smith 1234456677
The only alternative is loop the names list, calculate the maximum length of the String, and add whitespaces as needed after every name to ensure that all the numbers begin at the same column.
Using tabs has the disavantage that you cannot know a priori how many whitespace are equivalent to a tab, since it is dependent of the editor.
I have an array of String like so:
array[0] = "1 4"
array[1] = "2 0"
array[2] = "2 1"
array[3] = "4 2"
and would like to process the array and print out the second part of the array element
on the same line when the first part of the array element have duplicates, like this:
4
0 1
2
I've been trying ages to work this out but I keep getting more confused...
Processing is based on consecutive lines.
It looks like a straight-forward Java coding problem to me:
String lastKey = null;
for (String str : array) {
String[] parts = str.split(" ");
if (parts[0].equals(lastKey)) {
System.out.print(" ");
} else if (lastKey != null) {
System.out.println();
}
System.out.print(parts[1]);
lastKey = parts[0];
}
System.out.println();
This assumes that your input file is ordered on the first field ...
Looking at the comments, it looks like you could use MultiMaps and simplify the design
MultiMap mhm = new MultiHashMap();
for ( string line: array) {
String []pair = line.split(" ");
mhm.put(pair[0],pair[1]);
}
for (Collection coll = (Collection) mhm.values() ) {
//print all values from collection?
}
I would check index n and n+1 of the array list. Tokenize both the strings and compare the first elements. If the first elements are the same, you can print the second element from both the strings in one line.
I assume that you are not looking for 2 specifically as the first number and you want to check only consecutive elements of the list. Is that the case?