• (2 Pages)
  • +
  • 1
  • 2

Moving Away From Parallel Arrays Rate Topic: ***** 6 Votes

#1 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10804
  • View blog
  • Posts: 40,277
  • Joined: 27-December 08

Post icon  Posted 27 December 2009 - 01:29 PM

*
POPULAR

In this tutorial, we will be covering how to use Classes and Objects instead of Parallel Arrays. In order to teach
students how to use arrays, many instructors give assignments requiring to use two or three arrays in parallel to
represent attributes in what should be classes. While this type of assignment allows students to gain confidence
when using arrays, this type of approach becomes very cumbersome to use and difficult to manage, especially as the number of elements stored increases in size and more so as the use of resizable collections like ArrayLists come into play.

So let's go ahead and start out with a standard inventory program that uses parallel arrays to store price, quantity and name. This program will display a menu using a JOptionPane window requesting input for adding inventory, updating a current item's status, displaying the inventory, and quitting. If the user wants to update an item, we will display another menu asking for the index of the item to change. After we recieve the index, we will display another menu asking the user if they want to update the name, quantity or price, followed by a prompt for the new value. And as was the requirement when I did the assignment, we'll limit the size of the arrays to 10 items in inventory.
import javax.swing.JOptionPane;
public class Inventory{
	 public static void main(String[] args){
		  /*
			 As we can see, we are starting out with 3 parallel arrays representing quantity, price, and name.
			 Each element in an array lines up with the elements at the corresponding indices in the other two arrays.
			 So quantity[0] represents the same item as price[0] and name[0]
		  */
		  int[] quantity = new int[10]; //quantity defaults to 0 for all items
		  double[] price = new double[10]; //price defaults to 0 for all items
		  
		  //names default to null, so we can't use an item's name until it is assigned one
		  String[] name = new String[10]; 

		  boolean toContinue = true;
		  String input = "";
		  int menuItem = 0;
		  
		  //holds place so when elements are supposed to be added, the appropriate indices are updated
		  int counter = 0; 
		  
		  while(toContinue){ 
			   input = JOptionPane.showInputDialog("1) Add an item\n2) Modify an existing item\n3) Display inventory\n4) Exit");
			   
			   menuItem = Integer.parseInt(input); 
			   switch(menuItem){
					 case 1: //add an item
							 name[counter] = JOptionPane.showInputDialog("Enter the name of this item");
							 quantity[counter] = Integer.parseInt(JOptionPane.showInputDialog("Enter the quantity available for this item");
							 price[counter] = Double.parseDouble("Enter the price of this item");
							 counter++; //go to the next position
							 break; //jump out of the switch
					   
					  case 2: //modify existing item
						   //pick the item
						   int index = Integer.parseInt(JOptionPane.showInputDialog("Which item from 0-9 do you wish to modify?"));
						   
						   //set up the display for the item
						   String item = "Name: " + name[index] + "\nQuantity: " + quantity[index] + "\nPrice: " + price[index];
						   
						   //prompt for category to update
						   int category = Integer.parseInt(JOptionPane.showInputDialog(item + "\nModify:\n1) Name\n2) Quantity\n3) Price"));
						   
							//and effect the update
							   if(category == 1) name[index] = JOptionPane.showInputDialog("Enter a new name");
							   else if(category == 2) quantity[index] = Integer.parseInt(JOptionPane.showInputDialog("Enter a new quantity"));
							   else if(category == 3) price[index] = Double.parseDouble(JOptionPane.showInputDialog("Enter a new price"));
						   break; 
					   case 3: //display items
					   		String display = "";
					   		for(int i = 0; i < name.length; i++){
					   			//if there isn't a name for an item, we won't display it
					   			if(name[i] == null) break;
					   			display += name[i] + "\t" + quantity[i] + "\t" + price[i] + "\n"; 
					   			}
					   		 //if there are no items in inventory, display such		
					   		if(display.trim().length() != 0) JOptionPane.showMessageDialog(null, "There are no items in inventory");
					   		
					   		//otherwise, display what is in inventory
					   		else JOptionPane.showMessageDialog(null,"Name\tQuantity\tPrice\n" + display);
					   		break;
					   case 4: //exit
					   	   System.exit(0);
					   }
				}
				
		  }	
}


So far, this program isn't too bad. A few tedious things (beyond getting input) that I noticed included making the display String for a given item, like at this line String item = "Name: " + name[index] + "\nQuantity: " + quantity[index] + "\nPrice: " + price[index];. Consider this though- what would happen if there were no size limitations as to the number of items you could have in inventory (meaning we are now using ArrayLists in parallel instead of static arrays)? When you go to add or remove (which would be the next logical step) items, you wouldn't have to use a counter variable because the ArrayLists would automatically resize as soon as elements are added or removed from them. This gets a little sticky, however, when removing elements in the middle of the lists, as it is very easy to get attributes mixed up. For example, you could remove element 9 for the name list, but end up removing element 8 from the quantity and element 10 from the price list. This would completely mess up the data integrity and accuracy, plus it is very hard to debug this error.

Another logical step would be to sort the elements according to one of their attributes (name, quantity or price). Using parallel arrays, you have to enforce each step of the sort amongst all three arrays. So for example, if you sort the quantity array in ascending order, the changes aren't automatically affected throughout the other two arrays. This means that if you call Arrays.sort() on one array, it doesn't necessarily change the other two. And if you call Arrays.sort() on each of the three arrays, you have just sorted three arrays individually, so your name, qunatity and price array are all in order according to the values stored in them. However, you will have mismatched all the attributes from the item they are supposed to describe.

Now that we've seen the cons of parallel arrays, let's talk about the advantages of using classes instead. First off, the attributes representing each class are contained within the class. This means that the quantity, price and name cannot get mismatched like we saw when using parallel arrays. This also means that we only have to manage one collection, so it saves memory. Next, we can use methods to make our lives easier. This means that we can set up a toString() method in the class, and when invoked, it will return a nice formatted (to our specifications) String; and we can also use a single setter method so we can eliminate the group of if statements for updating an item. So in short, you are dealing with one variable that holds all the information and can have automated tasks set up instead of having to hard code each component as we saw above.

Now that we've discussed the advantages of classes, let's take a look into putting them into use. To start, we'll take a look at designing a class to model an Item.
public class Item{ 

   /*notice how each attribute is contained within the class.
	 by doing this, we don't have to worry about mismatching
	 the attributes as seen in parallel arrays
	*/
	private int quantity; 
	private double price;
	private String name;

   /*
	 when the class is created, the constructor is invoked.
	 this specific constructor allows for the specification of 
	 each attribute upon the creation of the object
	*/
	public Item(String name, int quantity, double price){
		 //initialize the attributes
		 this.name = name; 
		 this.price = price;
		 this.quantity = quantity;
	}

	/*
	  This constructor simply creates a default item
	  with a generic name, none in stock and no price set.
	  It calls the other Item() constructor through the use of
	  the keyword this
	*/
	public Item(){
	   this("New Item",0,0);
	}

  /*
	Basic getter and setter methods for each attribute
  */

  public void setName(String name){this.name = name;}
  public String getName(){return name;}
 
  public void setPrice(double price){this.price = price;}
  public double getPrice(){return price;}

  public void setQuantity(int quantity){this.quantity = quantity;}
  public int getQuantity(){return quantity;}

  /*
   this setter method is a little more advanced. it is designed to allow for an easy 
   update of the item by passing a param representing the attribute to update and the
   new value. 
   @params:
	  -int category: 1- Name, 2- Quantity, 3- Price
	  -String value: represents the new value; will be parsed to appropriate type   
  */

  public void update(int category, String value){
	 switch(category){
		 case 1:
			name = value;
			return;
		 case 2:
			  //value is converted to an int
			  quantity = Integer.parseInt(value); 
			  return;
		 case 3:
			  //value is converted to a double
			  price = Double.parseDouble(value);
			  return;
	   }
	}
  /*
	This toString() method makes it very easy to get formatted information about the 
	Item rather than having to go through each of the getter methods individually. 
	Returns name, quantity and price separated by tabs
  */
  public String toString(){
	   return name + "\t" + quantity + "\t" + price;
   }
	
}



After looking at the Item class, I notice how it is a lot more organized than using parallel arrays, plus it provides a little tighter control on the attributes and more usability through many of its methods, most notably the toString() and update() methods. Now let's redo our Inventory program using the Item class instead of Parallel arrays.

import javax.swing.JOptionPane;
public class Inventory{
	public static void main(String[] args){
		//notice how we only use one array instead of 3
		//and that the array type is the same as class name
		//for Item
		Item[] inventory = new Item[10];
		
		boolean toContinue = true;
		String input = "";
		int menuItem = 0;
		int counter = 0;
		
		while(toContinue){
			input = JOptionPane.showInputDialog("1) Add an item\n2) Modify an existing item\n3) Display inventory\n4) Exit");
			menuItem = Integer.parseInt(input); 
			switch(menuItem){
				case 1: //add an item
					/*
					 as we see here, we still need to get the input for each attribute
					 but we eliminate a few lines where we had to update each parallel array.
					 instead, we just create a new Item, and increment the counter in the same
					 statement. counter++ will execute after the item has been created in the
					 current index of counter. so if counter = 0, a new Item will be created 
					 at inventory[0], then counter increments to 1.
					 */
					String name = JOptionPane.showInputDialog("Enter the name of the item");
					int quantity = Integer.parseInt(JOptionPane.showInputDialog("Enter the quantity of the item"));
					double price = Double.parseDouble(JOptionPane.showInputDialog("Enter the price"));
					inventory[counter++] = new Item(name, quantity, price);		
					break;
					
				case 2: //modify an existing item
					int index = Integer.parseInt(JOptionPane.showInputDialog("Which item from 0-9 do you wish to modify?"));
					
					//notice how we just call the toString() method instead of having a line to set up the String display
					int category = Integer.parseInt(JOptionPane.showInputDialog(inventory[index].toString() + "\nModify:\n1) Name\n2) Quantity\n3) Price"));
					String value = JOptionPane.showInputDialog("Enter the new value");
					
					//notice how we use the update() method from the given Item and let it update its attributes internally
					//rather than messing around with determining what parallel array to update and how to parse the values
					inventory[index].update(category, value);
					break;
				
				case 3: //display items
					//notice how many fewer lines this takes up than iterating through each parallel array
					//and appending the information to the display String
					//Here, the toString() method comes in handy, plus having one array makes the task easier
					//So we have about 4 lines of code for this part total
					String display = "Name\tQuantity\tPrice\n";
					for(Item i: inventory){
                                            if(i != null)
                                                  display += i.toString() + "\n";
                                        }
					JOptionPane.showMessageDialog(null, display);
					break;
					
				case 4: //exit
					System.exit(0);
			}//end switch
		
		}//end while
	}
}


As we can see, this program gives us tighter control over each Item because we don't have to worry about keeping up with which indices represent each Item. This becomes increasingly important as we move onto using resizable collections like ArrayList, and as we attempt to sort the Items by a given attribute (or multiple attributes). We also have the convenience of using methods defined in the Item class, something we didn't have the luxury of doing when using parallel arrays.

By using classes instead of parallel arrays, you will begin to get a better handle on Object-Oriented Programming. This will help you as you continue your studies of Java, especially as you come across more advanced OO concepts like inheritance, abstraction and polymorphism, in addition to helping you better organize your program.

Is This A Good Question/Topic? 39
  • +

Replies To: Moving Away From Parallel Arrays

#2 gibson.nathan  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 8
  • View blog
  • Posts: 294
  • Joined: 06-October 09

Posted 07 March 2010 - 07:54 PM

very nice tutorial. really helps to have nice tutorials like these to help you understand new programming concepts.
Was This Post Helpful? 0
  • +
  • -

#3 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10804
  • View blog
  • Posts: 40,277
  • Joined: 27-December 08

Posted 08 March 2010 - 03:38 PM

I'm glad you found it helpful. :bigsmile:
Was This Post Helpful? 1
  • +
  • -

#4 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5932
  • View blog
  • Posts: 12,854
  • Joined: 16-October 07

Posted 19 March 2010 - 09:06 AM

Thank you.

I'm always trying to explain to new programmers why parallel arrays are a poor choice. It's nice to have a tutorial to point them at.
Was This Post Helpful? 3
  • +
  • -

#5 skyzer  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 25
  • Joined: 05-September 10

Posted 24 January 2011 - 07:08 AM

Hi. The idea is great, but your example isn't working, it gives errors. First of all that
int quantity = Integer.parseInt("Enter the quantity of the item");
double price = Double.parseDouble("Enter the price");

could be int quantity = Integer.parseInt(JOptionPane.showInputDialog("Enter the quantity of the item"));
double price = Double.parseDouble(JOptionPane.showInputDialog("Enter the price"));

After that i could add an item and then it brought me back to the menu. And when i press 3 to display an item, it gives me an error
Exception in thread "main" java.lang.NullPointerException
at inventory.Inventory.main(Inventory.java:58)
Was This Post Helpful? 1
  • +
  • -

#6 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10804
  • View blog
  • Posts: 40,277
  • Joined: 27-December 08

Posted 24 January 2011 - 07:13 AM

I fixed those typos. Sorry about that. :)

The NullPointerException occurred b/c I didn't check to make sure an Item wasn't null before appending the result of its toString() method to the display String. I added the extra check.
Was This Post Helpful? 2
  • +
  • -

#7 skyzer  Icon User is offline

  • New D.I.C Head

Reputation: 4
  • View blog
  • Posts: 25
  • Joined: 05-September 10

Posted 24 January 2011 - 07:37 AM

thanks. but why is the extra check needed? We have created items in the array. So the iterator then iterates from the 10th item which is null if we have created like 1 item only?
oh and \t isn't processed by JOptionPane. So name from quantity and price isn't tabbed. The workaround is to use JTextArea for example
JOptionPane.showMessageDialog(null, new TextArea(display,11, 2));
Was This Post Helpful? 1
  • +
  • -

#8 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10804
  • View blog
  • Posts: 40,277
  • Joined: 27-December 08

Posted 24 January 2011 - 07:44 AM

Actually, not necessarily. Creating an array is like creating an empty beer case. We still need to fill it with beer cans. And the NullPointerException is thrown when we invoke toString() on the null object, not when we display the JOptionPane. :)
Was This Post Helpful? 3
  • +
  • -

#9 JavaT  Icon User is offline

  • D.I.C Head

Reputation: -10
  • View blog
  • Posts: 70
  • Joined: 21-February 11

Posted 29 April 2011 - 01:55 PM

Fantastic tutorial :D Helped me out way more than the notes I have from college. Thanks for your help
Was This Post Helpful? 0
  • +
  • -

#10 jgonzalez498  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 43
  • Joined: 29-May 11

Posted 31 May 2011 - 07:48 PM

I understand the vast majority of what your saying but I have one question what does it mean when you use (this) ? Or can you redirect me somewhere thats good for understanding this basic concept o.o
Was This Post Helpful? 0
  • +
  • -

#11 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10804
  • View blog
  • Posts: 40,277
  • Joined: 27-December 08

Posted 01 June 2011 - 05:37 AM

The this keyword refers to the object rather than the class. For example, this.instanceVariable refers to the instance variable rather than perhaps a local variable. If I have a method with a param or local variable with the same name as the instance variable, the this keyword allows me to reference the instance variable. You might want to check out the Oracle tutorial for more on the this keyword.
Was This Post Helpful? 0
  • +
  • -

#12 jgonzalez498  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 43
  • Joined: 29-May 11

Posted 01 June 2011 - 09:53 AM

Ohhhh okay so by using the key word (this) your creating a local variable with the same name as your instance variable equal to each other?

 
public Item(String name, int  quantity, double  price)
{
  //initialize the attributes
  this.name = name;
  this.price = price;
  this.quantity = quantity;
}



So the keyword (this) us used at times to reference the instance variable correct o.o?
//as a side note 5:30am is early for some programming lol!
Was This Post Helpful? 0
  • +
  • -

#13 reppard  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 09-October 11

Posted 12 October 2011 - 10:00 AM

Thank you for this tutorial, I am currently trying to digest it all =). I have one question about your class Item. You have the getter and setter methods but I dont see where these methods are used or initialized. They aren't called on by the main class. Thank you for any help!
Was This Post Helpful? 0
  • +
  • -

#14 Fuzzyness  Icon User is offline

  • Comp Sci Student
  • member icon

Reputation: 669
  • View blog
  • Posts: 2,438
  • Joined: 06-March 09

Posted 12 October 2011 - 10:58 AM

View Postreppard, on 12 October 2011 - 12:00 PM, said:

Thank you for this tutorial, I am currently trying to digest it all =). I have one question about your class Item. You have the getter and setter methods but I dont see where these methods are used or initialized. They aren't called on by the main class. Thank you for any help!

The getter and setter methods are there because the fields in the Item class are Private, means they cannot be accessed outside of that class. So if you want to change one or get the fields value, you have to use the getters and setter method.

Say a company buys out another company. Obviously they will want to advertise their company with the products or add there own in. You can use the getter and setter methods to do so, So lets change the name and price of an item:
item1.setName("Fuzzy's Food");
item.setprice(4.99);
System.out.println("Name: " + item1.getName() + "\nPrice: $" + item1.getPrice());



That will change the name and the price of the item. If you did not have get and setter method then you would not be able to change them or even get the current values of the item. All you wold be able to do is create an item and call it's toString() to see what it is.
Was This Post Helpful? 1
  • +
  • -

#15 reppard  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 20
  • Joined: 09-October 11

Posted 13 October 2011 - 09:59 AM

View PostFuzzyness, on 12 October 2011 - 10:58 AM, said:

View Postreppard, on 12 October 2011 - 12:00 PM, said:

Thank you for this tutorial, I am currently trying to digest it all =). I have one question about your class Item. You have the getter and setter methods but I dont see where these methods are used or initialized. They aren't called on by the main class. Thank you for any help!

The getter and setter methods are there because the fields in the Item class are Private, means they cannot be accessed outside of that class. So if you want to change one or get the fields value, you have to use the getters and setter method.

Say a company buys out another company. Obviously they will want to advertise their company with the products or add there own in. You can use the getter and setter methods to do so, So lets change the name and price of an item:
item1.setName("Fuzzy's Food");
item.setprice(4.99);
System.out.println("Name: " + item1.getName() + "\nPrice: $" + item1.getPrice());



Got it, so in this particular program, the setter and getter methods are not used per-say but are included for damage control. I need to go read up on constructors it looks like. This is fun stuff, just gonna take a little doing and a lot of practice =)
That will change the name and the price of the item. If you did not have get and setter method then you would not be able to change them or even get the current values of the item. All you wold be able to do is create an item and call it's toString() to see what it is.

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2