Using the code from this link loading text file contents to GUI:
Map<String, String> sections = new HashMap<>();
Map<String, String> sections2 = new HashMap<>();
String s = "", lastKey="";
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
while ((s = br.readLine()) != null) {
String k = s.substring(0, 10).trim();
String v = s.substring(10, s.length() - 50).trim();
if (k.equals(""))
k = lastKey;
if(sections.containsKey(k))
v = sections.get(k) + v;
sections.put(k,v);
lastKey = k;
}
} catch (IOException e) {
}
System.out.println(sections.get("AUTHOR"));
System.out.println(sections2.get("TITLE"));
In case of if contents of input.txt:
AUTHOR authors name
authors name
authors name
authors name
TITLE Sound, mobility and landscapes of exhibition: radio-guided
tours at the Science Museum
Now I want to count the values in HashMap, but sections.size() counting all data line stored in text file.
I w'd like to ask how can I count the items, i.e. values v in sections? How can I get number 4, according to authors name?
Since the AUTHOR has a 1 to many relationship, you should map it to a List structure instead of a String.
For example:
Map<String, ArrayList<String>> sections = new HashMap<>();
Map<String, String> sections2 = new HashMap<>();
String s = "", lastKey="";
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
while ((s = br.readLine()) != null) {
String k = s.substring(0, 10).trim();
String v = s.substring(10, s.length() - 50).trim();
if (k.equals(""))
k = lastKey;
ArrayList<String> authors = null;
if(sections.containsKey(k))
{
authors = sections.get(k);
}
else
{
authors = new ArrayList<String>();
sections.put(k, authors);
}
authors.add(v);
lastKey = k;
}
} catch (IOException e) {
}
// to get the number of authors
int numOfAuthors = sections.get("AUTHOR").size();
// convert the list to a string to load it in a GUI
String authors = "";
for (String a : sections.get("AUTHOR"))
{
authors += a;
}
Related
In this code, I get all words from a file and count them. After, that write them and their frequencies in a file.
This code is doing what i want exactly but additionally it count all blank spaces and write them to file , too. How can i not include them?
String line;
BigDecimal count = new BigDecimal(0);
ArrayList<String> words = new ArrayList<String>();
Pattern pattern = Pattern.compile("[^a-zA-Z]", Pattern.CASE_INSENSITIVE);
while ((line = reader.readLine()) != null) {
String string1 = line.toLowerCase();
String string[] = pattern.split(string1);
for (String s : string) {
words.add(s);
}
}
Map<String, BigDecimal> map = new HashMap<String, BigDecimal>();
for (String s : words) {
BigDecimal x = new BigDecimal(1);
if (map.containsKey(s)) {
count = map.get(s);
map.put(s, count.add(x));
} else if (!map.containsKey(s)) {
map.put(s, x);
}
}
Map<String, BigDecimal> wordHistogram = map;
List<Entry<String, BigDecimal>> sortedWordHistogram = new LinkedList<Entry<String, BigDecimal>>(
wordHistogram.entrySet());
Collections.sort(sortedWordHistogram, (o1, o2) -> o2.getValue().compareTo(o1.getValue()));
Map<String, BigDecimal> inTxt = map;
for (Entry<String, BigDecimal> entry : sortedWordHistogram) {
inTxt.put(entry.getKey(), entry.getValue());
writer.write(entry.getKey() + " : " + entry.getValue() + "\n");
}
I believe it is efficient enough but any adjustment to make it better or more efficient is pleased.
Simply replace your regex ([^a-zA-Z]) with \\s+.
This will make sure all the spaces between the words are considered while splitting a line.
Also, you can simplify your code further by replacing the following lines:
Pattern pattern = Pattern.compile("[^a-zA-Z]", Pattern.CASE_INSENSITIVE);
while ((line = reader.readLine()) != null) {
String string1 = line.toLowerCase();
String string[] = pattern.split(string1);
for (String s : string) {
words.add(s);
}
}
with
while ((line = reader.readLine()) != null) {
String string[] = line.trim().toLowerCase().split("\\s+");
for (String s : string) {
words.add(s);
}
}
Note that I have also used trim() additionally in order to remove the leading and trailing whitespace characters from the line before splitting it.
I am loading text file contents to GUI and counting HashMap values using this code:
Map<String, ArrayList<String>> sections = new HashMap<>();
Map<String, String> sections2 = new HashMap<>();
String s = "", lastKey="";
try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
while ((s = br.readLine()) != null) {
String k = s.substring(0, 10).trim();
String v = s.substring(10, s.length() - 50).trim();
if (k.equals(""))
k = lastKey;
ArrayList<String> authors = null;
if(sections.containsKey(k))
{
authors = sections.get(k);
}
else
{
authors = new ArrayList<String>();
sections.put(k, authors);
}
authors.add(v);
lastKey = k;
}
} catch (IOException e) {
}
// to get the number of authors
int numOfAuthors = sections.get("AUTHOR").size();
// to count HashMap value
jButton1.addActionListener(new Clicker(numOfAuthors));
jButton1.doClick();
// convert the list to a string to load it in a GUI
String authors = "";
for (String a : sections.get("AUTHOR"))
{
authors += a;
}
jcb1.setSelectedItem(authors);
The ActionListener of jButton1 was borrowed from here.
Now I want to assign AUTHOR (the number of items in HashMap is 12, so jButton1 will add dynamic 12 jComboBoxes) values to dynamically created jComboBoxes.
I have tried this code:
BufferedReader br = new BufferedReader(new FileReader ("input.txt"));
String str=null;
int i = 0;
while( (str = br.readLine()) !=null ) {
String v = str.substring(12, str.length() - 61).trim();
if(i == 0) {
jcb1.setSelectedItem(v);
} else {
SubPanel panel = (SubPanel) jPanel2.getComponent(i - 1);
JComboBox jcb = panel.getJcb();
jcb.setSelectedItem(v);
}
i++;
}
But this code read from input.txt all lines (70 lines), but I want to assign just that 12 values from AUTHOR field and show them on jcb.
How can I solve it?
You shouldn't have to re-read the entire text file again in order to complete the setup of the GUI. I would just read the text file once, then use the Map<String, ArrayList<String>> sections = new HashMap<>(); object to complete the setup of the GUI.
This could be the process for you:
1) Read the entire file and return the sections HashMap.
2) Setup the jPanel2 by adding the SubPanels to it (e.g. based on the number of Authors).
3) Setup the JComboBox's by adding the data stored in the HashMap (e.g. the mapped ArrayList's).
For number 1), I would just create a method that reads the file and returns the HashMap.
Read The File
Example (Adapted from your other question here):
public Map<String, ArrayList<String>> getSections ()
{
Map<String, ArrayList<String>> sections = new HashMap<>();
String s = "", lastKey = "";
try (BufferedReader br = new BufferedReader(new FileReader("input.txt")))
{
while ((s = br.readLine()) != null)
{
String k = s.substring(0, 10).trim();
String v = s.substring(10, s.length() - 50).trim();
if (k.equals(""))
k = lastKey;
ArrayList<String> authors = null;
if (sections.containsKey(k))
{
authors = sections.get(k);
}
else
{
authors = new ArrayList<String>();
sections.put(k, authors);
}
// don't add empty strings
if (v.length() > 0)
{
authors.add(v);
}
lastKey = k;
}
}
catch (IOException e)
{
e.printStackTrace();
}
return sections;
}
GUI Setup
Note: This code can be put wherever you are setting up the GUI now, I'm just placing all in the method below for an example.
public void setupGUI ()
{
// read the file and get the map
Map<String, ArrayList<String>> sections = getSections();
// get the authors
ArrayList<String> authors = sections.get("AUTHOR");
// Setup the jPanel2 by adding the SubPanels
int num = authors.size();
jButton1.addActionListener(new Clicker(num));
jButton1.doClick();
// Setup the JComboBox's by adding the data stored in the map
for (int i = 0; i < authors.size(); i++)
{
int index = i;
// not sure if getComponent() is zero or 1-baed so adjust the index accordingly.
SubPanel panel = (SubPanel) jPanel2.getComponent(index);
// Not sure if you already have the JComboBox in the SubPanel
// If not, you can add them here.
JComboBox jcb = panel.getJcb();
jcb.setSelectedItem(authors.get(i));
}
}
Side Note: I'm not sure why you are creating 12 separate SubPanel's, each with its own JComboBox? Maybe you want to consider how you can better layout the GUI. Just a consideration. In either case, you can use the above examples are a starting point.
I want to retrieve some rows of a 2d array.
example: I have file named as "data.csv", which contains
age sex zipcode classtype
21 m 23423 1
12 f 23133 2
23 m 32323 2
23 f 23211 1
The below mentioned code will give output like this:
{age=[21,12,23,23],sex=[m,f,m,f],zipcode=[23423,23133,32323,23211],classtype=[1,2,2,1]}
Now I want to retrieve rows which have classtype 1 and store this values in a new 2d array.
like partition1={{21,m,23423,1},{23,f,23211,1}}
public class CsvParser {
public static void main(String[] args) {
try {
FileReader fr = new FileReader((args.length > 0) ? args[0] : "data.csv");
Map<String, List<String>> values = parseCsv(fr, " ", true);
System.out.println(values);
List<List<String>> partition1 = new ArrayList<>(25);
List<String> classTypes = values.get("classtype");
for (int row = 0; row < classTypes.size(); row++) {
String classType = classTypes.get(row);
if ("1".equals(classType)) {
List<String> data = new ArrayList<>(25);
data.add(values.get("age").get(row));
data.add(values.get("sex").get(row));
data.add(values.get("zipcode").get(row));
data.add(values.get("classtype").get(row));
partition1.add(data);
}
}
System.out.println(partition1);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Map<String, List<String>> parseCsv(Reader reader, String separator, boolean hasHeader) throws IOException {
Map<String, List<String>> values = new LinkedHashMap<String, List<String>>();
List<String> columnNames = new LinkedList<String>();
BufferedReader br = null;
br = new BufferedReader(reader);
String line;
int numLines = 0;
while ((line = br.readLine()) != null) {
if (StringUtils.isNotBlank(line)) {
if (!line.startsWith("#")) {
String[] tokens = line.split(separator);
if (tokens != null) {
for (int i = 0; i < tokens.length; ++i) {
if (numLines == 0) {
columnNames.add(hasHeader ? tokens[i] : ("row_"+i));
} else {
List<String> column = values.get(columnNames.get(i));
if (column == null) {
column = new LinkedList<String>();
}
column.add(tokens[i]);
values.put(columnNames.get(i), column);
}
}
}
++numLines;
}
}
}
return values;
}
}
FileReader file1 = new FileReader(file);
BufferedReader buffer = new BufferedReader(file1);
String line = "";
while ((line = buffer.readLine()) != null) {
StringBuilder sb = new StringBuilder();
String[] str = line.split(",");
if(str[0]!=null||str[1]!=null||str[2]!=null){
sb.append("'" + str[0] + "',");
sb.append("'" +str[1] + "',");
sb.append("'" +str[2] + "'");
}
CSV File Must to be split comma based it should be work
Once I changed Map<String, List<String>> values = parseCsv(fr, "\\s,", true); to Map<String, List<String>> values = parseCsv(fr, " ", true); I was able to get the data in the right format...
From there it was just a matter to read through each row of classtype, when I found a value that matched 1, I would pull out each property for the given row and add it to a List, forming a single row. This was then added to another List which would maintain all the matching rows, for example...
List<List<String>> partition1 = new ArrayList<>(25);
List<String> classTypes = values.get("classtype");
for (int row = 0; row < classTypes.size(); row++) {
String classType = classTypes.get(row);
if ("1".equals(classType)) {
List<String> data = new ArrayList<>(25);
data.add(values.get("age").get(row));
data.add(values.get("sex").get(row));
data.add(values.get("zipcode").get(row));
data.add(values.get("classtype").get(row));
partition1.add(data);
}
}
System.out.println(partition1);
Which outputs...
[[21, m, 23423, 1], [23, f, 23211, 1]]
If you're looking for a more automated method, then I'm afraid you're out of luck, as Map makes no guarantee about the order that the keys are stored, iterated.
Of course, instead of using a List<List>, you could use a List<Map> which would maintain the keys for each value, for example...
List<Map<String, String>> partition1 = new ArrayList<>(25);
List<String> classTypes = values.get("classtype");
for (int row = 0; row < classTypes.size(); row++) {
String classType = classTypes.get(row);
if ("1".equals(classType)) {
Map<String, String> data = new HashMap<>(25);
for (String key : values.keySet()) {
data.put(key, values.get(key).get(row));
}
partition1.add(data);
}
}
System.out.println(partition1);
Which outputs...
[{sex=m, classtype=1, zipcode=23423, age=21}, {sex=f, classtype=1, zipcode=23211, age=23}]
I want to find the size of each value from the key-value pair in Map<Integer, ArrayList<String>>. Simply writing list.size() does not work.
Here's my code:
public void getF() throws Exception {
BufferedReader br2 =
new BufferedReader(
new FileReader("/home/abc/NetBeansProjects/network1.txt"));
System.out.println("hello" +r.usr);
while ((s= br2.readLine()) != null) {
String F[]= s.split(":");
for (String uid : F) {
if (uid == F[0]) {
user.add(uid);
} else {
li = followee.get(Integer.valueOf(F[0]));
if (li == null) {
followee.put(Integer.valueOf(F[0]), li= new ArrayList<String>());
}
li.add(uid);
}
System.out.println(followee);
int g = li.size();
System.out.println("g:" +g);
[...]
}
}
}
Why am I not getting correct size on last line?
Try to follow the data structures, by keeping the variable as close to their usage.
(I know in other languages the convention is to declare them at the top.)
Here li should be kept at the begin of a while-step. And its more natural to handle f[0] outside the loop, instead of for+if. I think the latter put you on the wrong foot.
Set<String> user = new HashSet<>();
Map<Integer, List<String>> followee = new HashMap<>();
String s;
while ((s = br2.readLine()) != null) {
// s has the format "key:value value value"
String keyAndValues[] = s.split(":", 2);
if (keyAndValues.length != 2) {
continue;
}
Integer key = Integer.valueOf(keyAndValues[0]);
String values = keyAndValues[1];
user.add(keyAndValues[0]);
List<String> li = followee.get(key);
if (li == null) {
li = new ArrayList<>();
followee.put(key, li);
}
Collections.addAll(values.split(" +");
System.out.println(followee);
int g = li.size();
System.out.println("g:" + g);
//[...]
}
I have a problem with my code. I need to do several operations on a log file with this structure:
190.12.1.100 2011-03-02 12:12 test.html
190.12.1.100 2011-03-03 13:18 data.html
128.33.100.1 2011-03-03 15:25 test.html
128.33.100.1 2011-03-04 18:30 info.html
I need to get the number of visits per month, number of visits per page and number of unique visitors based on the IP. That is not the question, I managed to get all three operations working. The problem is, only the first choice runs correctly while the other choices just return values of 0 afterwards, as if the file is empty, so i am guessing i made a mistake with the I/O somewhere. Here's the code:
import java.io.*;
import java.util.*;
public class WebServerAnalyzer {
private Map<String, Integer> hm1;
private Map<String, Integer> hm2;
private int[] months;
private Scanner input;
public WebServerAnalyzer() throws IOException {
hm1 = new HashMap<String, Integer>();
hm2 = new HashMap<String, Integer>();
months = new int[12];
for (int i = 0; i < 12; i++) {
months[i] = 0;
}
File file = new File("webserver.log");
try {
input = new Scanner(file);
} catch (FileNotFoundException fne) {
input = null;
}
}
public String nextLine() {
String line = null;
if (input != null && input.hasNextLine()) {
line = input.nextLine();
}
return line;
}
public int getMonth(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
if (dtok.countTokens() == 3) {
String year = dtok.nextToken();
String month = dtok.nextToken();
String day = dtok.nextToken();
int m = Integer.parseInt(month);
return m;
}
}
return -1;
}
public String getIP(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
return ip;
}
return null;
}
public String getPage(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
return page;
}
return null;
}
public void visitsPerMonth() {
String line = null;
do {
line = nextLine();
if (line != null) {
int m = getMonth(line);
if (m != -1) {
months[m - 1]++;
}
}
} while (line != null);
// Print the result
String[] monthName = {"JAN ", "FEB ", "MAR ",
"APR ", "MAY ", "JUN ", "JUL ", "AUG ", "SEP ",
"OCT ", "NOV ", "DEC "};
for (int i = 0; i < 12; i++) {
System.out.println(monthName[i] + months[i]);
}
}
public int count() throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream("webserver.log"));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
while ((readChars = is.read(c)) != -1) {
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n')
++count;
}
}
return count;
} finally {
is.close();
}
}
public void UniqueIP() throws IOException{
String line = null;
for (int x = 0; x <count(); x++){
line = nextLine();
if (line != null) {
if(hm1.containsKey(getIP(line)) == false) {
hm1.put(getIP(line), 1);
} else {
hm1.put(getIP(line), hm1.get(getIP(line)) +1 );
}
}
}
Set set = hm1.entrySet();
Iterator i = set.iterator();
System.out.println("\nNumber of unique visitors: " + hm1.size());
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + " - ");
System.out.println(me.getValue() + " visits");
}
}
public void pageVisits() throws IOException{
String line = null;
for (int x = 0; x <count(); x++){
line = nextLine();
if (line != null) {
if(hm2.containsKey(getPage(line)) == false)
hm2.put(getPage(line), 1);
else
hm2.put(getPage(line), hm2.get(getPage(line)) +1 );
}
}
Set set = hm2.entrySet();
Iterator i = set.iterator();
System.out.println("\nNumber of pages visited: " + hm2.size());
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + " - ");
System.out.println(me.getValue() + " visits");
}
}
Any help figuring out the problem would be much appreciated as I am quite stuck.
I didn't read the code thoroughly yet, but I guess you're not setting the read position back to the beginning of the file when you start a new operation. Thus nextLine() would return null.
You should create a new Scanner for each operation and close it afterwards. AFAIK scanner doesn't provide a method to go back to the first byte.
Currently I could also think of 3 alternatives:
Use a BufferedReader and call reset() for each new operation. This should cause the reader to go back to byte 0 provided you didn't call mark() somewhere.
Read the file contents once and iterate over the lines in memory, i.e. put all lines into a List<String> and then start at each line.
Read the file once, parse each line and construct an apropriate data structure that contains the data you need. For example, you could use a TreeMap<Date, Map<Page, Map<IPAdress, List<Visit>>>>, i.e. you'd store the visits per ip address per page for each date. You could then select the appropriate submaps by date, page and ip address.
The reset method of BufferedReader that Thomas recommended would only work if the file size is smaller than the buffer size or if you called mark with a large enough read ahead limit.
I would recommend reading throught the file once and to update your maps and month array for each line. BTW, you don't need a Scanner just to read lines, BufferedReader has a readLine method itself.
BufferedReader br = ...;
String line;
while (null != (line = br.readLine())) {
String ip = getIP(line);
String page = getPage(line);
int month = getMonth(line);
// update hashmaps and arrays
}