P5: Remove TableRows containing Null/NaN - java

The aim is to return a clean table that only includes rows that have numeric data within them, from a nominated column.
The code below works for me. But I can’t help but feel there is a better way to do this. Any thoughts on a more elegant solution?
I have the code:
Table removeEmptyRows(Table data, String column_name)
{
IntList rows_to_remove = new IntList();
Table dataCopy = cloneTable(data);
for (int r = 0; r<dataCopy.getRowCount(); r++)
{
String value_string = dataCopy.getString(r, column_name);
///filter out the NaNs
if ( ! isNullOrBlank(value_string))
{
if ( ! isNumeric(value_string) )
{
rows_to_remove.append(r);
}
} else {
rows_to_remove.append(r);
}
}
rows_to_remove.sortReverse();
for (int r : rows_to_remove)
{
dataCopy.removeRow(r);
}
return dataCopy;
}
boolean isNumeric(String inputData) {
return inputData.matches("[-+]?\\d+(\\.\\d+)?");
}
private static boolean isNullOrBlank(String s)
{
return (s==null || s.trim().equals(""));
}

This question might be a better fit at the Code Review Stack Exchange (note that if you post there, please link between crossposts and make sure you post a true MCVE and make it clear that this is a Processing, not Java question), but I'll try to offer some input.
You can simplify your code by adding good rows instead of removing bad rows. Create the returnTable by copying just the columns from the inputTable, then loop over inputTable and only add the valid rows.
Also, take a look at this if statement:
if ( ! isNullOrBlank(value_string) ) {
if ( ! isNumeric(value_string) ) {
rows_to_remove.append(r);
}
}
else {
rows_to_remove.append(r);
}
This will keep a row in one case: if the value is not null or blank and if it is numeric. You can rewrite this logic using a single if statement:
if (!isNullOrBlank(rowValue) && isNumeric(rowValue)){
Putting it all together, it looks like this:
Table removeEmptyRows(Table inputTable, String columnName){
Table returnTable = cloneTable(inputTable);
returnTable.clearRows();
for (int row = 0; row < inputTable.getRowCount(); row++){
String rowValue = inputTable.getString(row, columnName);
if (!isNullOrBlank(rowValue) && isNumeric(rowValue)){
returnTable.addRow(inputTable.getRow(row));
}
}
return returnTable;
}
But note that this code isn't necessarily better than your code. It's not any faster. And if you understood your code, then that's the most important thing. If it works, don't worry too much about making it "more elegant". Just move on to the next thing.

Related

Is there a way to pass back 2 different data types from a method in java?

I am trying to populate an empty array in the first column with ordered numbers and write this back. This works, but I need the row location passed back too for reference in another method.
// Generate a customer/order number.
public static String[][] gen_cust_number(String[][] cust_order, int order_location)
{
for(int row = 0; row < cust_order.length; row++)
{
if (cust_order[row][0] == null)
{
cust_order[row][0] = Integer.toString(row + 1000);
order_location = row;
Gen.p("\n\n\tYour order number is : " + cust_order[row][0]);
break;
}
}
return cust_order;
}
I'm not very familiar with working with objects, pairs, and whatnot as I am still learning but have done some searching on it and am stumped in understanding how to do it.
I'm not 100% sure with what you're trying to achieve, but by reading the code I think what get_cust_number should do is
Generate new order to the very first empty order list.
Return the new order list and its index.
If this is right, you don't have to pass the String[][] back because the reference of this instance is what the caller side already know as it's passed in the parameters.
You can also remove the order_location param as it's never read inside the method.
So what you can do to make it work is to
Remove the order_location from params.
Return the index of added order instead of the array itself.
This results in the following code.
// Generate a customer/order number.
public static int gen_cust_number(String[][] cust_order)
{
for(int row = 0; row < cust_order.length; row++)
{
if (cust_order[row][0] == null)
{
cust_order[row][0] = Integer.toString(row + 1000);
Gen.p("\n\n\tYour order number is : " + cust_order[row][0]);
return row;
}
}
// cust_order is full
return -1;
}
In the calling side, you can do the following:
String[][] cust_order = /* Some orders according to your logic. */;
int cust_order_count = /* Number of the orders generated. */;
// Generate the order and this will be the new number of orders.
cust_order_count = gen_cust_number(cust_order);

Generate Unique Object ID

I'm trying to generate a new unique identifier for each object in a class, without using a static nextID field to just increment. Using that will create complications when unloading and unloading the program.
I came up with a solution to loop through the objects in a static method checking them all but for some unknown reason to me, it won't exit the while-loop.
I have been testing it in ideone.com here trying to create 5 objects to begin with, though it won't even create one.
Without having to go to the link to view the whole testing code, below is the method I'm using.
public static int newRandomID() {
int randomID = 0;
boolean notUnique = true;
while (notUnique) {
randomID = (int) (Math.random() * 999999 + 1);
for (Example e : examples) {
if (e.ID == randomID) {
notUnique = true;
break;
}
notUnique = false;
}
}
return randomID;
}
Have I just made a stupid mistake that I'm too blind to see, or is there a reason that this isn't working?
If all you need is a unique identifier (that need not be sequential) and it dosn't have to be an integer, have a look at java.util.UUID
your notUnique is bit confusing and i think you are doing it wrong in here
if (e.ID == randomID) {
notUnique = true;
break;
}
you dont need to break the statement if the id exists. i changed you code may be this helps.
int randomID = 0;
boolean ContinueLoop = true;
while (ContinueLoop) {
randomID = (int) (Math.random() * 999999 + 1);
boolean exist = false;
for (Example e : examples) {
if (e.ID == randomID) {
exist = true;
}else{
exist = false;
break;
}
}
if(exist==false){
ContinueLoop = false;
}else{
ContinueLoop = true;
}
}
return randomID;
Tried to execute your code (from the link you sent):
After you created and printed 50 new ids, I tried to generate 150,000 more:
for (int i = 0; i < 150000; i++)
new Example();
and... it works perfectly fine! Just took it a minute or so (which makes sense).
If I try to create only 15,000 records it works in less than a second.
Which leads me to the conclusion that miss rate is exponentially high and starts to be unbearable once you reach 15% of the ids capacity.
Don't continue with this solution.
Use a different approach such as a stored sequential number (if you store the records). If you don't store the records, I don't see a reason why not to use a static int variable.

Verifying row is not empty before adding new row

I'm developing a tool which is supposed to save the content from a JTable to a CSV file, I have this "add row" button to add a new row, but I need the last row to be filled on every cell and then be allowed to add a new row.
Here is the code I have, but this doesn't create the new row nor throw any errors on console.
private void btnAddRowActionPerformed(java.awt.event.ActionEvent evt) {
for(int i=0;i<=jTable1.getColumnCount();i++){
if(jTable1.isRowSelected(jTable1.getRowCount())){
do{
model.insertRow(jTable1.getRowCount(), new Object[]{});
} while(jTable1.getValueAt(jTable1.getRowCount(), i).equals(""));
}
}
}
Okay, so what you seem to be saying is, the user should not be allowed to add a new row until the last row is fully completed...
You existing loop doesn't make sense, basically, for each column, you are checking to see if the last row is selected, and inserting a new row for each column which is blank ("")...?
Remember, generally Java is zero indexed, this means, the last row is actually jTable1.getRowCount() - 1, so, it's unlikely that your if isRowSelected would be true, which is actually a good thing, cause otherwise you would have had a real mess...
Assuming I understand your question correctly (as it's a little vague), you could try something more like this...
boolean rowCompleted = true;
int lastRow = jTable1.getRowCount() - 1;
if (jTable1.isRowSelected(lastRow)) {
for (int col = 0; col < jTable1.getColumnCount(); col++) {
Object value = jTable.getValueAt(lastRow, col);
if (value == null || value.toString().trim().isEmpty()) {
rowCompleted = false;
break;
}
}
}
if (rowCompleted) {
// Insert new row...
} else {
// Show error message
}
Maybe use a TableModelListener.
Every time a cell is updated on the last row of the table you check to make sure all columns have data. If all columns have data you enable the "Add Row" button, otherwise you disenable the button.
I was checking this post and I used the code posted by MadProgrammer, but I made a few modifications and I got this working properly according to your need. If you want you can ask me for the project and I can happily provide it to you
private void btnAddRowActionPerformed(java.awt.event.ActionEvent evt) {
boolean rowCompleted;
int lastRow = jTable1.getRowCount()-1;
if(jTable1.isRowSelected(lastRow)){
for(int col=0;col<jTable1.getColumnCount();col++){
Object value = jTable1.getValueAt(lastRow, col);
if(value == null || value.toString().trim().isEmpty()){
rowCompleted=false;
}
else{
rowCompleted=true;
}
if(rowCompleted==true){
model.insertRow(jTable1.getRowCount(), new Object[]{});
}
else{
JOptionPane.showMessageDialog(null, "Something went worng. Try this:\n - Please select a row before adding new row.\n - Please verify there are no empty cells","Processing table's data",1);
}
break;
}
}
else{
JOptionPane.showMessageDialog(null, "Something went wrong. Verify this:\n - There is not any row selected.\n - You can only create new rows after last row","Processing table's data",1);
}
}
I hope this could help you, but first say thanks to MadProgrammer :D

Changing an array attempt

I posted this question up earlier and it was pretty much a lazy post as I didn't provide the code I had and as a result got negged pretty badly. Thought I'd create a new one of these ....
I have an array dogArray which takes ( name, secondname, dogname )
I want to be able to change the dogname:
here's my attempt :
public void changeName(Entry [] dogArray) {
Scanner rp = new Scanner(System.in);
String namgeChange = rp.next(); {
for (int i = 0; i < dogArray.length; i++){
for (int j = 0; j < dogArray[i].length; j++){
if (dogArray[i][j] == name){
dogArray[i][j] = nameChange;
}
}
}
}
For a start it doesn't like the fact I've used ' name ' although it is defined in the dogArray. I was hoping this would read input so that users are able to change 'name' to whatever they input. This will change the value of name in the array.
Do you guys think I'm getting anywhere with my method or is it a pretty stupid way of doing it?
Only one loop is necessary, also move your call to next.
public void changeName(Entry [] dogArray) {
Scanner rp = new Scanner(System.in);
for (int i = 0; i < dogArray.length; i++){
String nameChange = rp.next(); {
if(!dogArray[i].name.equals(nameChange)){
dogArray[i].name = nameChange;
}
}
}
You might want to make this function static as well and use accessors and mutators to change and get the name. Might want to tell the user what you want them to type as well. Also there is no point in testing if the name changed, if it changed then set it, if it didnt change then set it (it doesnt hurt). Just get rid of if and keep the code inside.

Java - For loop not executing when trying to search ArrayList

this is my first question on stack overflow but I have some experience in Java. I am making a Java application at the moment (575 lines and counting!) and am trying to search through an ArrayList for a string. But I do not want it to be exact! Let me clarify: I want to iterate through each ArrayList element and search that string for another string. if the string is found in the ArrayList element, (for now) I want it printed to the console. I hope I have been clear enough.
Following is the relevant code. All variables are defined and the code compiles, just no output (from the search function) is printed. I am pretty sure that it is because the for loop doesn't execute, but I am puzzled as to why.
//the keylistener that calls the search() function, attached to a JTextField that the query is entered into
class searchFieldListener implements KeyListener {
searchFieldListener() {
}
public void keyTyped(KeyEvent event) {
if (event.getID() == KeyEvent.KEY_TYPED) {
query = searchField.getText()+Character.toString(event.getKeyChar());
System.out.println(query);
for (i = 0; i == nameList.size(); i++) {
search(query, i);
}
}
}
public void keyReleased(KeyEvent event) {
}
public void keyPressed(KeyEvent event) {
}
}
//the troublesome search() function
void search(String query, int iter) {
searchString = nameList.get(iter);
System.out.println(searchString);
if (searchString.indexOf(query) != -1) {
System.out.println(Integer.toString(iter));
} else {
System.out.println("not found \n");
}
}
Variables/Objects and uses:
searchFieldListener
The KeyListener for the JTextField called searchField for obvious reasons.
query
The string of the text to be searched for.
i
Why does everyone use i in loops? I guess it's a coding tradition.
nameList
The ArrayList of names (well, duh).
searchString
The string to be searched in (as in, try to find query in searchString).
iter
The number of iterations the for loop has been through so far.
Once again I hope I have been clear enough. Thanks!
The reason why your for loop is not executing is because of the condition used in the loop:
for (i = 0; i == nameList.size(); i++)
^^
Since the size method of the ArrayList class returns the number of elements you might want to have
i < nameList.size() instead.
for (i = 0; i == nameList.size(); i++)
should be
for (i = 0; i < nameList.size(); i++)
Not sure if you need < or <= though, you just modify it to you needs.
have have a typo in your for-loop. shouldn't this:
for (i = 0; i == nameList.size(); i++) {
look like this:
for (i = 0; i < nameList.size(); i++) {
Several correct answers, but one aspect is missing:
for (i = 0; i < nameList.size(); i++)
This is an old-school loop. Starting from Java 1.5, you should use this idiom to iterate over an array or iterable (a List is an Iterable):
for(String s: strings){
}
This simpler syntax is a) much less error-prone and b) a common way to iterate over many different data structures, including arrays and collections.
Internally this is a shortcut for this code:
for(Iterator<String> it = strings.iterator(); it.hasNext();){
String s = it.next();
// your code here
}

Categories

Resources