How to Iterate Twice over Map values in Java - java

I know there are other solutions out there but nothing is working for me.
Question: In my main method, I group together IDs by rating and make the rating the key and the rest of the info the value as a List. When I create the hashmap and put in the lists I can accurately print the contents of the hashmap. However, once I pass the map the evaluate method, the values are lost and I cannot iterate in the same way that I did in the main method, even though the logic is the same. I am not experienced with the Map class in java. Can somebody please help me figure out why when I pass the Map to my evaluate method that I can no longer iterate the Map?
import java.io.*;
import java.util.*;
public class Evaluate {
public static double grandTotal;
public static void main(String[] args) throws Exception {
FileInputStream fs = new FileInputStream("testInput.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
FileInputStream fs2 = new FileInputStream("testTest.txt");
BufferedReader br2 = new BufferedReader(new InputStreamReader(fs2));
String line;
String line2;
String[] bloop;
String bleep;
String flooper;
String splitter;
String[] splitInput;
List<String> oneStarList= new ArrayList<String>();
List<String> twoStarList= new ArrayList<String>();
List<String> threeStarList= new ArrayList<String>();
List<String> fourStarList= new ArrayList<String>();
List<String> fiveStarList= new ArrayList<String>();
List<String> values2 = new ArrayList<String>();
try {
while ((line=br.readLine()) != null) {
bloop = new String[10];
bloop = line.split("\\s+");
bleep = bloop[1].toString();
flooper = (bloop[0]+" "+bloop[2]+" "+bloop[3]+" "+bloop[4]);
if (bleep.equals("1")){
oneStarList.add(flooper);
}
else if (bleep.equals("2")){
twoStarList.add(flooper);
}
else if (bleep.equals("3")){
threeStarList.add(flooper);
}
else if (bleep.equals("4")){
fourStarList.add(flooper);
}
else if (bleep.equals("5")){
fiveStarList.add(flooper);
}
grandTotal+=(Double.parseDouble(bloop[2]));
}
}
catch (Exception e){
}
Map<String,List<String>> hmap = new HashMap<String,List<String>>();
hmap.put("1",oneStarList);
hmap.put("2", twoStarList);
hmap.put("3", threeStarList);
hmap.put("4", fourStarList);
hmap.put("5", fiveStarList);
while ((line2=br2.readLine()) != null) {
splitInput = new String[5];
splitInput = line2.split("\\s+");
evaluate(splitInput[0],splitInput[1],hmap);
}
br.close();
br2.close();
}
public static void evaluate(String movID, String usrID, Map<String,List<String>> hash) throws Exception{
FileWriter fw = new FileWriter("outputTest.txt");
BufferedWriter bwr = new BufferedWriter(fw);
List<String> values = new ArrayList<String>();
List<String> outputList = new ArrayList<String>();
String[] floop;
String fleep;
int movIDtotal=0;
int usrIDtotal=0;
int totalValues=0;
double pmovIDStar=0;
double pusrIDStar=0;
double pmovID=0;
double pusrID=0;
double numID=0;
double keyTotalProb=0;
String keyOutputStr;
String keyHold;
final Set<Map.Entry<String,List<String>>> entries = hash.entrySet();
for (String key : hash.keySet()){
values = hash.get(key);
System.out.println(key + ":");
for (int i=0;i<values.size();i++){
System.out.println(values.get(i));
floop = new String[5];
fleep = values.get(i);
floop = fleep.split("\\s+");
if (movID.equals(floop[0])){
movIDtotal++;
totalValues++;
}
if (usrID.equals(floop[0])){
usrIDtotal++;
totalValues++;
}
}
values.clear();
}
for (Map.Entry<String, List<String>> entry: entries){
values= entry.getValue();
keyHold = entry.getKey();
for (int j=0;j<values.size();j++){
floop = new String[5];
fleep = values.get(j);
floop = fleep.split("\\s+");
if (movID.equals(floop[0])){
pmovIDStar = Double.parseDouble(floop[3]);
numID = Double.parseDouble(floop[1]);
pmovID = (numID/movIDtotal);
}
if (usrID.equals(floop[0])){
pusrIDStar = Double.parseDouble(floop[3]);
numID = Double.parseDouble(floop[1]);
pusrID = (numID/usrIDtotal);
}
}
keyTotalProb = ((totalValues/grandTotal)*(pmovIDStar)*(pusrIDStar))/(pusrID*pmovID);
keyOutputStr = Double.toString(keyTotalProb);
outputList.add(keyHold);
outputList.add(keyOutputStr);
values.clear();
}
double max = Double.MIN_VALUE;
for (int m=0;m<outputList.size();m+=2){
double coolguy = Double.parseDouble(outputList.get(m+1));
int index = 0;
if(coolguy>max){
max = coolguy;
index = m;
}
try {
bwr.write(String.format("%-1s %-1s %-1s%n", movID,usrID,outputList.get(index)));
bwr.close();
fw.close();
}
catch(Exception e) {
}
}
}
}
Backup info: I'm trying to build a java program that essentially performs the final stage of the Naive Bayes algorithm to predict user ratings (1-5) for movies. I have used MapReduce to train data and now I have an input file where each line contains a string containing information in this order without the commas (movie or user id,rating , number of times rating and ID occur together in total, number of times ID occurs in total, probability that ID and rating occur together out of all ratings for ID). Essentially this is the classification stage.

never suppress excetions. especially when you do coding/debugging.
catch (Exception e){ } is very bad practice
When you do:
final Set<Map.Entry<String,List<String>>> entries = hash.entrySet();
it does not copy hash.entrySet to entries. It creates another reference to it.
same is for values= entry.getValue();
then what do you expect after your first loop (and others too)?
when you do:
values.clear();
your values gone from the lists which are in hash and since entries is just a reference to hash.entrySet() you have what you've done - empty lists.

Related

Sorting a 2D string array in Java in descending order and writing it to a file

So I have to read out a string from a file in Java. It's for a highscore system.
Each line of the file contains something similiar like this: "24/Kilian".
The number in front of the / is the score and the text after the / is the name.
Now, my problem is that I have to sort the scores descending and write them back into the file. The new scores should overwrite the old ones.
I tried it but I can't get it working properly.
I already wrote some code which reads the score + name line by line out of the file.
public static void sortScores() {
String [][]scores = null;
int i = 1;
try (BufferedReader br = new BufferedReader(new FileReader("score.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
scores[i][0] = line.substring(0, line.indexOf("/"));
scores[i][1] = line.substring(line.indexOf("/"), line.length());
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
So, this code basically writes the score and the name in a 2D array like this:
score[0][0] = "24";
score[0][1] = "Kilian";
score[1][0] = "33";
score[1][1] = "Name";
score[2][0] = "45";
score[2][1] = "AnotherName";
I hope someone can help me with my problem.
You can use java.util.Arrays's sort-Method:
Arrays.sort(scores, (a, b) -> -a[0].compareTo(b[0]));
But this lead to the case that "3" will be above "23". So probably you should create new class which holds the value and use an ArrayList
I'd recomend you to make a new class Score which holds your data (score + name) and add a new instance of Score into a ArrayList for each row you read from the file. After that you can implement a Comparator and sort your ArrayList. It's much easier because you don't know how big your string array will get and you need to know that when you're working with arrays.
public class Score {
public Score(int score, String name) {
this.score = score;
this.name = name;
}
int score;
String name;
// getter
}
List<Score> scoreList = new ArrayList<>();
String line;
while ((line = br.readLine()) != null) {
scoreList.add(new Score(Integer.parseInt(line.substring(0, line.indexOf("/"))), line.substring(line.indexOf("/"), line.length())));
}
Collections.sort(scoreList, new Comparator<Score>() {
public int compare(Score s1, Score s2) {
return s1.getScore() - s2.getScore();
}
}
// write to file
You can try it:
HashMap<Integer, String > map = new HashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader("score.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
String[] lines = line.split("/");
map.put(Integer.valueOf(lines[0]),lines[1]);
}
SortedSet<Integer> keys = new TreeSet<Integer>(map.keySet());
keys.forEach(k -> System.out.println(map.get(k).toString() + " value " + k ));
Use Arrays.sort(arr, comparator) with a custom comparator:
Arrays.sort(theArray, new Comparator<String[]>(){
#Override
public int compare(final String[] first, final String[] second){
// here you should usually check that first and second
// a) are not null and b) have at least two items
// updated after comments: comparing Double, not Strings
// makes more sense, thanks Bart Kiers
return Double.valueOf(second[1]).compareTo(
Double.valueOf(first[1])
);
}
});
System.out.println(Arrays.deepToString(theArray));

How to delete the duplicate data in arraylist java

public class TestArticles {
public static void handlewords() throws IOException {
String path = "C:\\Features.txt";
String path1 = "C:\\train.txt";
String path2 = "C:\\test.txt";
File file = new File(path2);
PrintWriter pw = new PrintWriter(file);
Features ft = new Features();
String content = ft.readFile(path);
String [] words = content.split(" ");
FileReader fr = new FileReader(path1);
BufferedReader br = new BufferedReader(fr);
String line = null;
while ((line = br.readLine()) != null) {
String [] word = line.split(" ");
List<String> list1 = new ArrayList<String>(words.length);
List<String> list2 = new ArrayList<String>(word.length);
for(String s: words){
list1.add(s);
HashSet set = new HashSet(list1);
list1.clear();
list1.addAll(set);
}
for(String x: word){
list2.add(x);
HashSet set = new HashSet(list2);
list2.clear();
list2.addAll(set);
}
boolean first = true;
pw.append("{");
for(String x: list1){
for(String y: list2){
if(x.equalsIgnoreCase(y)){
if(first){
first = false;
} else {
pw.append(",");
}
pw.append(list1.indexOf(x) + 39 +" "+ "1");
}
}
}
pw.append("}");
pw.append("\r\n");
pw.flush();
}
br.close();
pw.close();
}
My output file something like:
{23 1,35 1,56 1,56 1,...}
{2 1,4 1,7 1,...}
The first line some data duplicated, the second line all the data in order without duplicated data. How can I delete those duplicated data? I already used hashset, however it did not work.
The items in your list1 and list2 are correctly unique, but in a case sensitive way. So you might have items in it like man and Man. But then in your last loop you use x.equalsIgnoreCase(y), and since "man".equalsIgnoreCase("man") and "man".equalsIgnoreCase("MAn") are both true, that's how duplicates appear.
There are several ways to fix that:
When you build list1 and list2, lowercase the items
Or, use a TreeSet instead of HashSet, with a comparator that ignores case
Change x.equalsIgnoreCase(y) to x.equals(y)
Try override equals on your Hashsets, like this:
HashSet set = new HashSet(list1){
public boolean equals(Object o) {
return this.toString().equals(o.toString());
};
};

How to print the values of the List<List<String[]>> in java?

I want to get the values of the individual arrays from the list and utilize them
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import au.com.bytecode.opencsv.CSVReader;
public class ReadCSV {
public static void main(String[] args) {
String startFile = "/Users/ray/Downloads/hello.csv";
//String outFile = "./outData.xml";
try {
CSVReader reader = new CSVReader(new FileReader(startFile));
String[] line = null;
String[] header = reader.readNext();
List<List<String[]>> out = new ArrayList<List<String[]>>();
while((line = reader.readNext())!=null){
List<String[]> item = new ArrayList<String[]>();
for (int i = 0; i < header.length; i++) {
String[] keyVal = new String[2];
String string = header[i];
System.out.println("the value of the header : "+string);
String val = line[i];
System.out.println("the value of the field : "+val);
keyVal[0] = string;
keyVal[1] = val;
item.add(keyVal);
}
out.add(item);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have a csv file of the following format:-
Keyword,AlternateKeywords---> these are the header fields
apple,banana
orange,ego kit
ego ce4,venus
demo,cat
I want the Arrays in form of:
array[] keyword={apple,orange,ego ce4,demo}
array[] banana={banana,ego kit,venus,cat}
I do not know how to get the data from the List 'out' and get the values and print the elements as above. It can be any number of headers and any number of elements for that particular column, the above csv is just an example.
Please help me if possible.
Take a look on your structure:
array[] keyword={apple,orange,ego ce4,demo}
array[] banana={banana,ego kit,venus,cat}
You dont need 3D like List<List<String[]>> but only 2D List<List<String>>
Here is working code
public static void main(String[] args) {
String startFile = "C:\\workspacePrototype\\some.csv";
try {
CSVReader reader = new CSVReader(new FileReader(startFile));
String[] line = null;
String[] headers = reader.readNext();
List<List<String>> build = new ArrayList<List<String>>();
List<String> tempArr;
// generate headers
for(String header : headers){
tempArr = new ArrayList<String>();
tempArr.add(header);
build.add(tempArr);
}
// generate content
while((line = reader.readNext())!=null){
for (int i = 0; i < build.size(); i++) {
tempArr = build.get(i);
String val = line[i];
tempArr.add(val);
build.set(i, tempArr);
}
}
System.out.println(Arrays.asList(build));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Output:
[[[Keyword, apple, orange, ego ce4, demo], [AlternateKeywords, banana, ego kit, venus, cat]]]
[EDIT]
BTW, you can create some class like:
public class Column{
private String mName;
private List<String> mData;
// get/set
}
and instead
List<List<String>> build = new ArrayList<List<String>>();
use like:
List<Column> build = new ArrayList<Column>();
by this way Column class should store column name to mName and data to mData

Adding text read from a file to an array list in java

I am having trouble putting text read from a file into an array list.
My text looks like this:
438;MIA;JFK;10:55;1092;447
638;JFK;MIA;19:45;1092;447
689;ATL;DFW;12:50;732;448 etc...
My code looks like this:
package filesexample;
import java.io.*;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.ArrayList;
/**
*
* #author
*/
public class FilesExample {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
File file = new File ("/Schedule.txt");
try
{
Scanner scanner= new Scanner(file);;
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
Scanner lineScanner= new Scanner(line);
lineScanner.useDelimiter(";");
while(lineScanner.hasNext()){
String part = lineScanner.next();
System.out.print(part + " ");
}
System.out.println();
}
}catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
Some help on getting started would be much appreciated thank you!
You don't need to do the following
Scanner lineScanner= new Scanner(line);
lineScanner.useDelimiter(";");
Just do
String[] parts = line.split(";");
They all need to have there own array for each category, so flight
number will need its own array, origin its own array
I would say, don't. You don't need to have separate array for each of them.
I would rather create a class with attributes: -flight number, origin, destination, time, miles and price.
Now for every line, I would just split it on ;, and have a constructor in the class that takes an array as parameter. And rather than having separate ArrayList for each of those parameters, I would have an ArrayList of that class instance.
class Flight {
private int flightNumber;
private String origin;
private String destination;
... so on for `time, miles and price`
public Flight(String[] attr) {
this.flightNumber = Integer.parseInt(attr[0]);
this.origin = attr[1];
this.destination = attr[2];
... so on.
}
}
And then where you are using: -
Scanner lineScanner = new Scanner(line);
lineScanner.useDelimiter(";");
I would use String#split() to get individual attributes, and then create an ArrayList<Flight>, and add Flight instance to it: -
List<Flight> flights = new ArrayList<Flight>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] attributes = line.split(";");
flights.add(new Flight(attributes));
}
NOTE : -
You can improve upon how you instantiate your Flight class, and how you set different attributes. Since your attributes are of different types, and they are in String form, so you would need to use appropriate conversion from String to Integer or String to double which I have not considered here.
use String.split(delimiter) to split your String.
List<String> list = new ArrayList<String>();
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
String[] strArr = line.split(";");
for(String s: strArr){
list.add(s); //adding a string into the list
System.out.println(s + " ");
}
}
System.out.println();
EDIT: From your comments
of the text I posted, the first number is flight number, origin, destination, time, miles and price. They all need to have
there own array for each category, so flight number will need its own
array, origin its own array etc.
you don't need an array for each property. create a class and name it Filght. and make your properties as instance variables.
class Flight {
private long filghtNo;
private String origin;
private dest;
private Date time;
private long miles;
private double price;
//setters and getters
}
List<Flight> list = new ArrayList<Flight>();
Flight flight = new Flight();
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
Scanner scan = new Scanner(line);
if(scan.hasNextLong()){
flight.setFilgthNo(scan.nextlong());
}
else if // do the same for other properties
}
list.add(flight);
This way is more Object Oriented.
I re-iterate the need for a more OO approach but here is what you need for what you asked for.
public final class FlightInfoParser {
private static final String[] EMPTY_STRING_ARRAY = new String[]{};
public static void main(String[] args) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
List<String> flightNumbersList = new ArrayList<String>();
List<String> originsList = new ArrayList<String>();
List<String> destinationsList = new ArrayList<String>();
List<String> departureTimesList = new ArrayList<String>();
List<Integer> milesList = new ArrayList<Integer>();
List<Double> pricesList = new ArrayList<Double>();
String line;
while ((line = r.readLine()) != null) {
String[] fields = line.split(";");
flightNumbersList.add(fields[0]);
originsList.add(fields[1]);
destinationsList.add(fields[2]);
departureTimesList.add(fields[3]);
milesList.add(Integer.parseInt(fields[4]));
pricesList.add(Double.parseDouble(fields[5]));
}
String[] flightNumbersArray = flightNumbersList.toArray(EMPTY_STRING_ARRAY);
String[] originsArray = originsList.toArray(EMPTY_STRING_ARRAY);
String[] destinationsArray = destinationsList.toArray(EMPTY_STRING_ARRAY);
String[] departureTimesArray = departureTimesList.toArray(EMPTY_STRING_ARRAY);
int[] milesArray = new int[milesList.size()];
for (int i = 0, len = milesArray.length; i < len; ++i) {
milesArray[i] = milesList.get(i);
}
double[] pricesArray = new double[pricesList.size()];
for (int i = 0, len = pricesArray.length; i < len; ++i) {
pricesArray[i] = pricesList.get(i);
}
}
}

Java - Saving StringTokenizer into arrays for further processing in other methods

I've been coding Perl and Python a lot and this time I got an assignment to code in Java instead. So I'm not too familiar with handling data in Java.
My task involves having a input file where I need to check dependencies and then output those with transitive dependencies. Clearer ideas below:
Input File:
A: B C
B: C E
C: G
D: A
Output File:
A: B C E G
B: C E G
C: G
D: A B C E G
So far this is what I've got (separating the first and second token):
import java.util.StringTokenizer;
import java.io.*;
public class TestDependency {
public static void main(String[] args) {
try{
FileInputStream fstream = new FileInputStream("input-file");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
while ((strLine = br.readLine()) != null) {
StringTokenizer items = new StringTokenizer(strLine, ":");
System.out.println("I: " + items.nextToken().trim());
StringTokenizer depn = new StringTokenizer(items.nextToken().trim(), " ");
while(depn.hasMoreTokens()) {
System.out.println( "D: " + depn.nextToken().trim() );
}
}
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
}
Any help appreciated. I can imagine Perl or Python to handle this easily. Just need to implement it in Java.
This is not very efficient memory-wise and requires good input but should run fine.
public class NodeParser {
// Map holding references to nodes
private Map<String, List<String>> nodeReferenceMap;
/**
* Parse file and create key/node array pairs
* #param inputFile
* #return
* #throws IOException
*/
public Map<String, List<String>> parseNodes(String inputFile) throws IOException {
// Reset list if reusing same object
nodeReferenceMap = new HashMap<String, List<String>>();
// Read file
FileInputStream fstream = new FileInputStream(inputFile);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
// Parse nodes into reference mapping
while((strLine = br.readLine()) != null) {
// Split key from nodes
String[] tokens = strLine.split(":");
String key = tokens[0].trim();
String[] nodes = tokens[1].trim().split(" ");
// Set nodes as an array list for key
nodeReferenceMap.put(key, Arrays.asList(nodes));
}
// Recursively build node mapping
Map<String, Set<String>> parsedNodeMap = new HashMap<String, Set<String>>();
for(Map.Entry<String, List<String>> entry : nodeReferenceMap.entrySet()) {
String key = entry.getKey();
List<String> nodes = entry.getValue();
// Create initial node set
Set<String> outSet = new HashSet<String>();
parsedNodeMap.put(key, outSet);
// Start recursive call
addNode(outSet, nodes);
}
// Sort keys
List<String> sortedKeys = new ArrayList<String>(parsedNodeMap.keySet());
Collections.sort(sortedKeys);
// Sort nodes
Map<String, List<String>> sortedParsedNodeMap = new LinkedHashMap<String, List<String>>();
for(String key : sortedKeys) {
List<String> sortedNodes = new ArrayList<String>(parsedNodeMap.get(key));
Collections.sort(sortedNodes);
sortedParsedNodeMap.put(key, sortedNodes);
}
// Return sorted key/node mapping
return sortedParsedNodeMap;
}
/**
* Recursively add nodes by referencing the previously generated list mapping
* #param outSet
* #param nodes
*/
private void addNode(Set<String> outSet, List<String> nodes) {
// Add each node to the set mapping
for(String node : nodes) {
outSet.add(node);
// Get referenced nodes
List<String> nodeList = nodeReferenceMap.get(node);
if(nodeList != null) {
// Create array list from abstract list for remove support
List<String> referencedNodes = new ArrayList<String>(nodeList);
// Remove already searched nodes to prevent infinite recursion
referencedNodes.removeAll(outSet);
// Recursively search more node paths
if(!referencedNodes.isEmpty()) {
addNode(outSet, referencedNodes);
}
}
}
}
}
Then, you can call this from your program like so:
public static void main(String[] args) {
try {
NodeParser nodeParser = new NodeParser();
Map<String, List<String>> nodeSet = nodeParser.parseNodes("./res/input.txt");
for(Map.Entry<String, List<String>> entry : nodeSet.entrySet()) {
String key = entry.getKey();
List<String> nodes = entry.getValue();
System.out.println(key + ": " + nodes);
}
} catch (IOException e){
System.err.println("Error: " + e.getMessage());
}
}
Also, the output is not sorted but that should be trivial.
String s = "A: B C D";
String i = s.split(":")[0];
String dep[] = s.split(":")[1].trim().split(" ");
System.out.println("i = "+i+", dep = "+Arrays.toString(dep));

Categories