i'm trying to create a void method that will read csv file and count the reputaion number of state such that how many times TX,how many times Oh and how many times of Dc. the out should be-TX=4; Oh=2;DC=2. but my out put is "For input string: "F" "- and i really couldn't get where is the problem.can someone help me?
"Crimerate.csv"
State county Rate
Tx,DALLAs,39
TX,Aderson,10
Oh,Archer,20
DC,DC,50
Tx,Houston,31
TX,Claude,13
Oh,Bexar,10
DC,SE,40
public static void countnumber()
{
try{
List<String>number=Files.readAllLines(Paths.get("Crimerate.csv"));
double sum=0,num=0;
for (String line:number){
if(num==0){
++num;
continue;
}
line=line.replace("\"","");
String []result=line.split(",");
double close = Double.parseDouble(result[6]);
String numberAsString = Double.toString(close);
if(numberAsString.equals("Tx"))
{
sum++;
System.out.println("number of Tx =" + sum);
}
else if(numberAsString.equals("Oh"))
{
sum++;
System.out.println("number of Oh =" + sum);
}
else if(numberAsString.equals("Dc"))
{
sum++;
System.out.println("number of Dc =" + sum);
}
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main (String args[])
{
countnumber();
}
While the previously suggested answers will address the specific question of why there was only a single response (a result of having only a single sum variable), they have two issues.
They are not accounting for the fact that in the example data, Texas is shown both as "Tx" and "TX". Thus, the current other answers will not give the correct result of 4 for Texas (they will only show 2).
The approaches assume that the full data set was shown. If other states are present, then the code would need to be continually expanded to support the new states.
This solution handles both situations.
public static void main(String[] args)
{
Map<String, Integer> countByState = new HashMap<>();
List<String> number;
try {
number = Files.readAllLines(Paths.get("f:/tmp/Crimerate.csv"));
int cntr = 0;
for (String line : number) {
// skip first line
if (cntr++ == 0) {
continue;
}
String []result=line.split(",");
// should add error checking
String state = result[0].toUpperCase();
Integer cnt = countByState.get(state);
if (cnt == null) {
cnt = new Integer(0);
}
countByState.put(state, ++cnt);
}
System.out.println(countByState);
}
catch (IOException e) {
e.printStackTrace();
}
}
Sample Results based upon the data presented in the question (there is only one DC in that data):
{TX=4, OH=2, DC=1}
int txCount = 0;
int ohCount = 0;
int dcCount = 0; //create this variables inside the class(instance variables)
if(numberAsString.equals("Tx"))
{
++txCount;
System.out.println("number of Tx =" + txCount);
}
else if(numberAsString.equals("Oh"))
{
++ohCount;
System.out.println("number of Oh =" + ohCount);
}
else if(numberAsString.equals("Dc"))
{
++dcCount;
System.out.println("number of Dc =" + dcCount);
} //its better if u use equalsIgnoreCase on if Statements
you were referring to same sum variable on each if loops, i have fixed that .
i assume that the code you have written on reading the file is correct.
You just need different sum variables for each sum. And print the results after the loop.
try{
List<String>number=Files.readAllLines(Paths.get("Crimerate.csv"));
double sumTx=0,sumOh=0,sumDc=0,num=0;
for (String line:number){
if(num==0){
++num;
continue;
}
line=line.replace("\"","");
String []result=line.split(",");
double close = Double.parseDouble(result[6]);
String numberAsString = Double.toString(close);
if(numberAsString.equals("Tx")) {
sumTx++;
} else if(numberAsString.equals("Oh")){
sumOh++;
} else if(numberAsString.equals("Dc")){
sumDc++;
}
}
System.out.println("number of Tx =" + sumTx);
System.out.println("number of Oh =" + sumOh);
System.out.println("number of Dc =" + sumDc);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
Related
I have been trying to figure this out for hours and I have had no luck doing so,
I'm trying to iterate over my Arraylist<Booking> which utilizes my Booking class file and trying to understand how I'm able to search it for the matching, case-insensitive term.
this is my current method:
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
for (int i = 0; i < bookings.size(); i++) {
while (!bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
i++;
if (bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
String output = String.format("%-30s%-18s%-18b$%-11.2f\n", bookings.get(i).getStudent(), bookings.get(i).getLessons(), bookings.get(i).isPurchaseGuitar(), bookings.get(i).calculateCharge());
this.taDisplay.setText(heading + "\n" + output + "\n");
}
}
}
}
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
I know it's messy but, just trying to make do.
I am trying to retrieve the name of the booking as I am searching by name as well as provide an error message if that names does not exist, to do that I must
use bookings.getStudent().getName() I have had some luck as I can return the value but now I am not able to provide my error message if I do not find it. Any help is appreciated.
package com.mycompany.mavenproject1;
public class Booking {
private Student student;
private int lessons;
private boolean purchaseGuitar;
// CONSTANTS
final int firstDiscountStep = 6;
final int secondDiscountStep = 10;
final int tenPercentDiscount = 10;
final int twentyPercentDiscount = 5;
final double LESSON_COST = 29.95;
final double GUITAR_COST = 199.00;
double LESSON_CHARGE = 0;
final int MINIUMUM_LESSONS = 1;
public Booking() {
}
public Booking(Student student, int lessons, boolean purchaseGuitar) {
this.student = new Student(student.getName(), student.getPhoneNumber(), student.getStudentID());
this.lessons = lessons;
this.purchaseGuitar = purchaseGuitar;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public int getLessons() {
return lessons;
}
public void setLessons(int lessons) {
this.lessons = lessons;
}
public boolean isPurchaseGuitar() {
return purchaseGuitar;
}
public void setPurchaseGuitar(boolean purchaseGuitar) {
this.purchaseGuitar = purchaseGuitar;
}
public double calculateCharge() {
double tempCharge;
if (lessons < firstDiscountStep) {
LESSON_CHARGE = (lessons * LESSON_COST );
} else if (lessons < secondDiscountStep) {
tempCharge = (lessons * LESSON_COST) / tenPercentDiscount;
LESSON_CHARGE = (lessons * LESSON_COST) - tempCharge;
} else {
tempCharge = (lessons * LESSON_COST) / twentyPercentDiscount;
LESSON_CHARGE = (lessons * LESSON_COST) - tempCharge;
}
if (isPurchaseGuitar()) {
LESSON_CHARGE += GUITAR_COST;
}
return LESSON_CHARGE;
}
#Override
public String toString() {
return student + ","+ lessons + "," + purchaseGuitar +"," + LESSON_COST;
}
}
If I understood you correctly, you are searching for a given student name in your collection of bookings. And if it is present, set a formatted text.
First of all, use a for-each loop, because you don't use the index.
Secondly, return from the for-each loop, when you found your student.
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
for (final Booking booking : bookings) // for-each
{
if (booking.getStudent().getName().equalsIgnoreCase(searchTerm))
{
String output = booking.getFormattedOutput();
this.taDisplay.setText(heading + "\n" + output + "\n");
return; // break out of the loop and method and don't display dialog message
}
}
}
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
Then there are multiple other things, which you could improve.
Don't get all the data from a booking just to format it externally. Let the Booking class handle the formatting and return you the string you desire. (move the formatting in a function inside the Booking class)
Instead of recreating a Student you receive in your Booking constructor, make the Student class immutable, and then you can just reuse the object provided.
Try also making the Booking class immutable. You provided some setters, but do you really want to change the student in a booking? Or would you rather create a new booking for the other student?
The calculteCharge method could be stateless. Just get the LESSON_CHARGE value and hold it in a local variable. Your method would also get threading-proof.
Make your constants final and better yet make them members of the class (by adding the static modifier) instead of every member.
Lastly, representing a money amount with a floating (double is better but not good either) number, you will run into funny situations. Try this calculation: 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 for example.
One way would be to create a Money class which holds the value in cents as an integer. And when you want to display the amount you can divide it by 100 and format it accordingly. That way, you can also restrict it become negative.
PS: Sometimes we desperately try to find a solution that we don't give ourselves some rest. After a little break, you might recognize the problem. Oh and try debugging with breakpoints. Or this, if you use IntelliJ IDEA (which I would highly recommend, the community edition is free).
You're re-incrementing your counter variable, which is really not going to help. Try the following:
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
boolean studentFound = false;
for (int i = 0; i < bookings.size(); i++) {
if (bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
String output = String.format("%-30s%-18s%-18b$%-11.2f\n", bookings.get(i).getStudent(),
bookings.get(i).getLessons(), bookings.get(i).isPurchaseGuitar(),
bookings.get(i).calculateCharge());
this.taDisplay.setText(heading + "\n" + output + "\n");
studentFound = true;
break;
}
}
}
if (!studentFound) {
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
}
This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}
So I have been trying to sort this out for a couple of hours now and I'm sure its something really simple or just a simple mistake i am missing but i have a three class program, control, account and MyThreads.
Im trying to have multipule threads(cards) modify the single account, i'm trying to use a monitor so only one thread can make changes at a time, this is not what i have archived I have somehow just allowed the one thread to access the account class and no others, they seem to just disappear, i assume they are just all on wait but refuse to wake up... any help before i implode?
account code:
class account{
private static int value = 0;
private static int cards = 0;
private static int count = 0;
private static int lock = 0;
public void setValue(int temp){
value = temp;
}
public int getValue(){
// while(lock == 1){
// try{
// wait();
// }catch (InterruptedException e){
// }
// }
return value;
}
synchronized public void withdraw(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value - temp;
count++;
System.out.println(count + "(" + tempID +")"+" "+temp+" - "+value);
lock = 0;
this.notifyAll();
}
synchronized public void deposit(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value + temp;
count++;
System.out.println(count + "(" + tempID +")"+" - "+temp+" "+value);
lock = 0;
this.notifyAll();
}
public void setCards(int temp){
cards = temp;
}
public int getCards(){
return cards;
}
public int getCount(){
return count;
}
}
control code:
class control{
public static void main(String [] args){
account acc = new account();
acc.setValue(1000);
acc.setCards(5);
// if(args.length > 0){
// try{
// int tempCards = Integer.parseInt(args[0]);
//
// }catch (NumberFormatException e) {
// System.err.println("Number of Cards : " + args[0] + " must be an integer.");
// System.exit(1);
// }
// try{
// int tempVal = 0;
// tempVal = Integer.parseInt(args[1]);
// acc.setValue(tempVal);
// }catch (NumberFormatException e) {
// System.err.println("Account Value : " + args[1] + " must be an integer.");
// System.exit(1);
// }
// }else{
// System.err.println("No values found, please start program with the number of Cards and Bank Account Value, both in integer format");
// System.exit(1);
// }
System.out.println("Transaction Withdrawal Deposit Balance");
System.out.println(" " + acc.getValue());
for(int i=0; i<=((acc.getCards())-1); i++){
new MyThreads(Integer.toString(i+1));
}
}
}
MyThreads code:
class MyThreads implements Runnable{
private String ID;
private Thread t;
account acc = new account();
MyThreads(String tempID){
ID = tempID;
t = new Thread(this, ID);
t.start();
}
public void run(){
try{
for (int i = 0; i < 20; i++){
if(Math.random()>0.5){
int tempW = 0;
tempW = ((int)(Math.random()*100));
acc.withdraw(tempW, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+tempW+" -"+acc.getValue());
}else{
int tempD = 0;
tempD = ((int)(Math.random()*100));
acc.deposit(tempD, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+" - "+tempD+" "+acc.getValue());
}
t.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Thread " + ID + " interrupted.");
}
System.out.println("Thread " + ID + " exiting.");
}
}
I know its a mess, forgive me im lazy.
Have a look at the definition of a Monitor in Java. In your code, you use the keyword synchronized for two methods, which are the same as:
public void XX(){
lock.lock(); // lock is a private variable
try {
// code here
} finally {
lock.unlock();
}
}
In short, It is a shorthand for explicit locking and will prevent multiple threads to access the methods concurrently.
So, just remove the lock part (i.e. the while(lock==1) block) inside your synchronized methods and it will work. Also, if in other codes you need a real lock, use the Lock class, not an integer.
For more information, there are a lot of good introduction to multithreading on the web, for example this one.
Your question, and thus answer, is a wonderful mixture of static synchronized and wait-notify that's neve being called. Why use static? sounds like a magic word? skip static and make life easier.
Also note that a wait-notify is related to a specific object; if wait-notify are related to different objects they will not communicate. Have a single object that they all synchronize around.
So, I made this code almost work, but I want to use insertion sort on the array and for the output to display results sorted by product ID only by insertion sort. Each product ID should have the same corresponding number of units. The units should not be sorted independently. The only order would be by product ID is what I'm basically implying.
import java.util.*;
import java.io.*;
class newversion {
public static int [][] table; // the output table
public static int numOfRows; //number of rows used up in the table
public static int lookfor(int productID){
int location = -1; //-1 an error
for(int i = 0; i < numOfRows; i++){
if (table[i][0] == productID){
location = i;
}
}
return location;
}
/*
here is my modified bubble sort code. I based it on this, but done differently:
http://stackoverflow.com/questions/23283655/bubble-sort-on-2d-array-java
public static void swap(int int1, int int2, int[] array) {
if(int1 == int2){
return;
}
else{
int temp = int2;
array[int2] = array[int1];
array[int2] = temp;
}
}
but it didn't work and I had to try something else
*/
public static boolean contains(int productID){
if (lookfor(productID) == -1){
return false;
}
return true;
}
public static void main(String[] args) {
File file = null;
Scanner scanner = null;
try{
file = new File("data.csv");
scanner = new Scanner( file );
}
catch(Exception e){
System.out.println("Error opening file!");
System.exit(1);
}
//citation of idea for sorting method in 2D array: http://stackoverflow.com/questions/23283655/bubble-sort-on-2d-array-java
//I'm using bubble sort on a 2D array
//this is his code
/*
private static void bubblesort(Integer[] array) {
for (int i = 0; i < array.length; i++) {
for(int j = 0; j < array.length - 1; j++) {
if(array[j].compareTo(array[j+1]) > 0) {
swap(j, j+1, array);
}
}
}
}
private static void swap(Integer int1, Integer int2, Integer[] array) {
if(int1 == int2)return;
Integer temp = new Integer(array[int2]);
array[index2] = array[int1];
array[int1] = temp;
}
*/
//here's my idea for bubble sort on a 2D array
/*
for (int i = 0; i < numOfRows; i++){
for(int j = 0; j < numOfRows - 1; j++) {
if(table[j][0].compareTo(array[j+1][0]) > 0) {
swap(j, j+1, table);
}
}
//this didn't work well either
//Now, I have to try another for-loop
*/
//Count the number of lines in the file
int size_of_file = 0;
while (scanner.hasNextLine()){
scanner.nextLine();
size_of_file++;
}
table = new int[size_of_file][2];
//reset scanner
try{
file = new File("data.csv");
scanner = new Scanner( file );
}
catch(Exception e){
System.out.println("Error opening file!");
System.exit(1);
}
//save the title
String titleLine = scanner.nextLine();
System.out.println(titleLine);
//for each line in the file, store and total it.
numOfRows=0;
while (scanner.hasNextLine()){
String ln = scanner.nextLine();
String[] row = ln.split(",");
System.out.println(row[0] + ", " + row[1]);
if (contains(Integer.parseInt(row[0]))){
//This is the location in the table where the product id exists already.
int location = lookfor(Integer.parseInt(row[0]));
//add the units to what we have in the table
table[location][1] += Integer.parseInt(row[1]);
}
else{
table[numOfRows][0]= Integer.parseInt(row[0]);
table[numOfRows][1]= Integer.parseInt(row[1]);
numOfRows++;
}
}
//output
try{
PrintWriter output = new PrintWriter("output.csv");
output.println(titleLine);
for(int i=0;i<numOfRows;i++){
output.println(table[i][0] + "," + table[i][1]);
}
output.close();
}
catch(Exception e){
System.out.println("Error writing file");
}
}
}
I want to understand how to use FileReader better. I read a little bit about it here:
https://www.caveofprogramming.com/java/java-file-reading-and-writing-files-in-java.html
https://bytes.com/topic/java/answers/585814-reading-data-into-array-file
Although I don't think I understand from that how to store it into an array. Could someone explain how I can store values from FileReader class into an array? I want it in a 2D array where the number of rows is just however many product IDs I have and there is always 2 columns.
Excel File to read from:
Product ID Units
10002 4
10004 6
10008 2
10010 3
10010 3
output I get right now:
Product ID Units
10002 20
10004 72
10008 12
10010 37
10007 28
20003 42
30019 56
30020 29
10006 36
20005 32
etc.
I apologize if this update should be posted as a different question. Let me know so I can go by community standards. The piece of output I posted, you'll notice isn't sorted by productID. That's the last thing I want to do. Other than that, it basically works. I am apologizing in case someone wants to vote me down for not posting the answer, since technically it would be the same answer to the initial question. If this update should be a different thread, again, let me know and I'll make the edit.
I cant figure out how to start a method to delete a specific entry stored in an array...
I used to do this:
public void deleteEntry() {
SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[i] = null;
}
}
}
but I was advised not to assign the entry[i] to null because it will ruin my entries...
I have no idea how to code it in another way...
What should I need to do is:
I need to delete a specific entry from an array
please help...
also... its output was error it says:
Exception in thread "main" java.lang.NullPointerException
at AddressBook.viewAll(AddressBook.java:62)
at AddressBook.main(AddressBook.java:36)
Java Result: 1
This is my code in my main program:
public class AddressBook {
private AddressBookEntry entry[];
private int counter;
private String SName;
public static void main(String[] args) {
AddressBook a = new AddressBook();
a.entry = new AddressBookEntry[100];
int option = 0;
while (option != 5) {
String content = "Choose an Option\n\n"
+ "[1] Add an Entry\n"
+ "[2] Delete an Entry\n"
+ "[3] Update an Entry\n"
+ "[4] View all Entries\n"
+ "[5] View Specific Entry\n"
+ "[6] Exit";
option = Integer.parseInt(JOptionPane.showInputDialog(content));
switch (option) {
case 1:
a.addEntry();
break;
case 2:
a.deleteEntry();
break;
case 3:
a.editEntry();
break;
case 4:
a.viewAll();
break;
case 5:
a.searchEntry();
break;
case 6:
System.exit(1);
break;
default:
JOptionPane.showMessageDialog(null, "Invalid Choice!");
}
}
}
public void addEntry() {
entry[counter] = new AddressBookEntry();
entry[counter].setName(JOptionPane.showInputDialog("Enter name: "));
entry[counter].setAdd(JOptionPane.showInputDialog("Enter add: "));
entry[counter].setPhoneNo(JOptionPane.showInputDialog("Enter Phone No.: "));
entry[counter].setEmail(JOptionPane.showInputDialog("Enter E-mail: "));
counter++;
}
public void viewAll() {
String addText = " NAME\tADDRESS\tPHONE NO.\tE-MAIL ADD\n\n";
for (int i = 0; i < counter; i++) {
addText = addText + entry[i].getInfo() + "\n";
}
JOptionPane.showMessageDialog(null, new JTextArea(addText));
}
public void searchEntry() {
int notfound = 0;
SName = JOptionPane.showInputDialog("Enter Name to find: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, entry[i].getInfo2());
break;
} else {
notfound++;
}
}
if (notfound != 0) {
JOptionPane.showMessageDialog(null, "Name Not Found!");
}
notfound = 0;
}
public void editEntry() {
int notfound = 0;
SName = JOptionPane.showInputDialog("Enter Name to edit: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
entry[i] = new AddressBookEntry();
entry[i].setName(JOptionPane.showInputDialog("Enter new name: "));
entry[i].setAdd(JOptionPane.showInputDialog("Enter new add: "));
entry[i].setPhoneNo(JOptionPane.showInputDialog("Enter new Phone No.: "));
entry[i].setEmail(JOptionPane.showInputDialog("Enter new E-mail: "));
break;
} else {
notfound++;
}
}
if (notfound != 0) {
JOptionPane.showMessageDialog(null, "Name Not Found!");
}
notfound = 0;
}
public void deleteEntry() {
SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[i] = null;
break;
}
}
}
}
Assigning the values to null is going to be the easiest practice. If you're really picky, you could resize the array, but that would be rather pointless. Just keep a separate size counter and decrement it each time you set something to null.
Another reason you're getting a null pointer exception is that you have to consider what's happening when you're replacing values in your array with null but still iterating by counter. You're going to be left with holes in your array upon deletion. The first solution would be to bypass null values altogether, and just shift your array down (somewhat of an expensive operation). The second would be to alter your methods to take those null values into consideration. Example:
public void viewAll() {
String addText = " NAME\tADDRESS\tPHONE NO.\tE-MAIL ADD\n\n";
int nonNull = 0;
for (int i = 0; i < entry.length; i++) {
if (entry[i] != null) {
addText = addText + entry[i].getInfo() + "\n";
nonNull++;
}
if (nonNull == counter) break;
}
JOptionPane.showMessageDialog(null, new JTextArea(addText));
}
I don't have a compiler on this computer, so consider it more of psuedo-code. But the idea is that the counter is only keeping track of how many non-null values you have in your address book, and that these null values could be in random places of your array. I added the nonNull integer as a local counter to keep track of how many values you've encountered that aren't null (so you aren't forced to run through the entire address book). Then, I added the if statement to ensure that the value at entry[i] isn't a null value (trying to invoke getInfo() on a null value is what's giving you that error). Lastly, I added the if statement to break the loop if you've encountered all of the non-null values you have stored. Hope this helps. (Also it may be worth considering a LinkedList to eliminate the null values all together).
Actually, for simplicity's sake, you probably are much better off using a LinkedList, unless you are required to use an array, since you would need to alter all of your methods to take null spaces in your array into account. Assuming you're familiar with LinkedLists of course.
Arrays are immutable. You can change the value for a particular index in the array but you can't change the array size itself. To "delete", you could do:
myArray[index] = null;
And just treat null values as unset/deleted entries.
Assigning to null (currently what you are doing) is the proper thing to do. That will eliminate the reference to the object at that index and allow it to be garbage collected.
Replace entry[i] = null; with this:
System.arraycopy(entry, i + 1, entry, i, counter - i - 1);
--counter;
entry[counter] = null; // optional; helps with garbage collection
--i; // required to not skip the next element
(I'm assuming here that counter is the number of valid entries in entry. This will leave no null entries among the first counter elements of entry (assuming that there weren't any to start with).
Further thought: If you need the array length to always match the number of valid entries, you'll have to re-allocate the array and copy the values over. Just use arraycopy to copy entries from 0 through i-1 and from i+1 to counter-1 into the new array and then assign it to entry. This isn't particularly efficient and is best avoided if possible.
Better to this is List which has remove() method. But if you really want use Array I recommend you change Array to List and then remove all values, after it you can always change List to Array
import javax.swing.JOptionPane;
public class Test {
private static User[] entry = new User[] { new User("Gil"),
new User("Bil"), new User("John") };
public static void main(String... args) {
final Test test = new Test();
test.deleteEntry();
for (int index = 0; index < entry.length; index++) {
User user = entry[index];
if (user != null)
System.out.println(entry[index]);
}
}
public void deleteEntry() {
String SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int index = 0; index < entry.length; index++) {
if (entry[index].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[index] = null;
break;
}
}
}
private static class User {
private String name;
public User(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
}