Creating multi dimensional arrays with multiple data forms in Java - java

I am working on a project to help get me back into Java coding and it is a text based game (I know, not much, but I have to start somewhere).
Anyway, I have come across a problem. I need to be able to put names of parts (it is a hardware tycoon game) and prices along with them into an array. For example, a desktop computer has parts such as a CPU, and the game would list your CPU choices. I need a way of storing this data, and it's pretty complicated to me because I need to not only store all of the names of CPUs for the player's benefit, but also store the prices alongside the names. On top of that, I have multiple product types such as desktops, laptops, and consoles, which each pretty much have different part names and prices.
I thought of a 3 dimensional array to store the product types such as desktop (in columns), the part names (in rows), and the prices (behind the rows, if that makes sense in a 3 dimensional way. But I do not know how to initialize such an array and how to set the values on initialization.
Also, I thought of creating classes for each product type and putting arrays in each class to define parts and prices (2d arrays), but it is still complex and I would like to know how to sort this data and potentially make a system where certain parts are unlocked as game time progresses. Thank you in advance.

I might take you in a different direction. Why don't you create classes and objects? Then create instances of those objects? Java is an object oriented language. Creating objects would allow you to hold all of the values you need. Quick example,
Public abstract class CPU {
// Declare fields
private float price;
private String name;
// Declare constructors
}
Public class intelCPU extends CPU {
// GetPrice
public int getPrice() {
return price;
}
// Set Name
public void setName(n) {
name = n;
}
}

I agree with #Regis that you should be using a custom object to describe your products, and then storing them in a some kind of data structure.
However, you can solve the problem you described by declaring a multi-dimensional array of the type "Object," which will allow you to put basically anything into it, even primitives (autoboxing and autounboxing was added in Java 5 and will seamlessly translate between primitive types like int and the Java wrapper class for that type, like java.lang.Integer).
Of course such an array would be very weakly typed and there would be nothing stopping you from adding doubles to the product name column, or vice versa. You'd also have to do a lot of casting, which is a code smell.

How about using a Map instead. A Map let's you store information in Key/Value pairs. You can make a Map that has a key type of String (that represents the product type) and a value type of Map (that represents individual products) that has a String key (product name) and a value that stores the price (perhaps a double) or the info (as a String or something). That way you can do something like outerMap.get("laptops").get("laptop1") and that would return the information of laptop1. The first get, gets the Map that contains all of the laptop products (or whatever product type ypu would want). The second returns the information for the specific product in that category.
You can implement this like this.
Map<String, Map<String, String>> productMap = new HashMap<>();
Using this you would place a product type like this:
productMap.put("laptops", new HashMap<String,String>());
And then add a product like this:
productMap.get("laptops").put("laptop1","This is information about laptop 1");
PS: In case you aren't aware, the reason I used = new HashMap instead of = new Map is because Map is an interface not a class. A HashMap is a class that implements the Map interface.

More than multidimensional arrays, you could tag this with Object Oriented Programming (OOP). From your description it looks like you would need a class hierarchy, something like:
abstract class Product
class Desktop extends Product
class Laptop extends Product
class Console extends Product
Put all common fields/methods that can be used by Desktop, Laptop, Console etc into your Product class.
//Just an example
abstract class Product {
String name;
ArrayList<Component> components;
public String getName(){
return name;
}
}
Since each product has several components the product needs to have a list of components as shown above.
abstract class Component{
Double price;
public Double getPrice(){
return price;
}
}
Now you can have components like CPU, Power supply etc, they have some common behavior and fields like price that is put into Component class. Any specialized behavior / fields for each component can be put into the corresponding class like clock frequency shown below:
class CPU extends Component {
Double clockFreq;
}
So if your list of parts is 3 items long it could be written to a text file like so:
name,type,price
intelCPU6600,CPU,200
amdCPU7789,CPU,150
PS1Power,PSU,120
newPart,unknown,500
This list could be 100's of items without any problem. Read it into your program using Scanner & for each line do something like:
String line = scanner.nextLine();
String[] fields = line.split(",");
if("CPU".equals(fields[1]){
CPU cpu = new CPU(fields[0],fields[1],fields[2]);
//Product is an object of the class Product that you should have created earlier
product.components.add(cpu);
} else if("PSU".equals(fields[1]) {
PSU psu = new PSU(fields[0],fields[1],fields[2]);
product.components.add(psu);
} //..so on
if there is a generic product that you don't have a class for that's where the abstract class can be used:
if("unknown".equals(fields[1]){
Component comp = new Component(fields[0],fields[1],fields[2]);
product.components.add(comp);
}

Related

How to override addAll function in Java?

For instance I have two Arraylists with different data types.
ArrayList<Integer> intValues = new ArrayList<Integer>();
intValues.add(1);
intValues.add(2);
intValues.add(3);
ArrayList<String> strValues = new ArrayList<String>();
strValues.add("4");
strValues.add("5");
strValues.add("6");
If both of these lists contained the same data type objects, I would easily call addAll function;
intValues.addAll(intValues2);
But of course if I try to call addAll function with these different type lists, compiler warns me with incompatible types: ArrayList cannot be converted to Collection<? extends Integer> warning.
So I have to create a bad solution like;
for(String s: strValues)
{
intValues.add(Integer.parseInt(s));
}
Is there a better way to do this, I mean, creating a class which implements List, overriding addAll function etc. so I will be able to call;
intValues.addAll(strValues);
And intValues list will contain 1,2,3,4,5,6.
Edit: I really don't want to store String values in an Integer array, I have to deal with some creepy old code at the moment and I need a Collection to hold some differend kinds of classes, trying to create a Constructor for those objects, this integer-string scenario is just a simple way to introduce my problem.
Let me tell you about my current situation with another integer-string like scenario:
Creepy class A is car, it holds car's weight, price, color, engine type.
Creepy class B is watch, it holds watch's still type, movement type, price, lug size etc.
I am trying to create a holder class, so it will hold those classes and adding a few functions (for example, overriding compare method makes the holder class to compare prices of different classes).
Now I think I have to create a HolderHolder class which implements List so I can call holderHolder.addAll(carsList) and holderHolder.addAll(watchesList), and it will hold these as Holder objects and yes, this does not look pretty.
You act as if what you want is self-evident and logical. It really isn't. "4" and 4 are entirely unrelated, and expecting that your list of integers now has a value 4 when you call addAll with "4" is, as a consequence, as bizarre as expecting your list of movies to gain 'Forrest Gump' when you call .addAll(colorsOfTheRainbow) on that, because in your mind, 'green' is so incredibly similar to 'Forrest Gump', that you might as well assume that. (Here, 'green' is "4" and 'Forrest Gump' is 4).
So let's do some work and make this more sensible:
That 'assumption' (that "4" is so similar to 4, that you want .add("4") to just mean that 4 shows up in your list) needs to encoded, explicitly, in your code. Now it makes sense, and now you can write a function that maps Green to Forrest Gump and use it for that example just the same - we've generalized the principle.
What you're really talking about is a mapping function that maps an element of your List<String> (so.. a String) to a type that your target list is of (Integer), and you then want the operation: Take this list. Map every value in it with my mapping function. Then, add all the mapped values to this other list.
That makes perfect sense.
So, write that.
List<Integer> intValues = ...;
strValues.map(Integer::valueOf).forEachOrdered(intValues::add);
Looks like bad smell.
One bad Solution can be an own implementation of an List with Type Object. But than you have to cast and work with the Classes of the primitive types.
I think i every case you have to parse or cast. That cost to much of performance just for easy call of addAll.
I would think about the incoming data and why they have to be the same but in different types?
Edit:
If i get to know it correct. It is a little bit hard to understand without more detailed infos.
But maybe you can write an mapper class to map thoose old creepy classes in one new class an then you can put these new class in an collection and can compare all by overriding equals.
public class CreepyClassMapper
{
public CreepyClassMapper(Car aCar, Watch aWatch)
{
}
#override
private boolean equals(Object obj)
{
// maybe add an instance check
CreepyClassMapper other = (CreepyClassMapper) object;
// do your compare stuff
return true;
}
}
if i were you, i will create a function like this in util class
public void append(ArrayList<Integer> intValues, ArrayList<String> strValues){
}

Dynamic class vs hardcoded fields Java

I have a program that recruits witness accounts of a crime scene from various subjects.
Every kind of subject has its own Report class. For example:
public class EyeWitnessReport extends AbstractReport {
private String details;
private String relation;
private QuestioningResults questioningResults;
private Integer stressLevel;
private EnumSet<CrimeFacts> crimeFacts;
private Religion religion; //to see if swearing on the Bible is an issue
}
public class ExpertWitnessReport extends AbstractReport {
private Expertise fieldOfExpertise;
private boolean relatedToAccused;
private List<Conflict> conflicts;
}
The main function of my app takes all the reports and merges them together into one CrimeScene class that contains all the details of the crime scene (by priorities, etc)
public CrimeScene mergeReports(List<AbstractReport> sources){
//takes all the reports in sources and returns one CrimeScene with the most relevant fields
}
My question is, the CrimeScene class is basically made up of data from the reports, after certain logic. It has 70 possible fields (the fields of every type of report) although on average only around 10-20 are filled.
Plus it has 2-3 fields of it's own (creationTime, reportingOfficer, etc...)
How should I go about implementing it?
Is it a better implementation to make CrimeScene a regular class (70 hardcoded fields, of which no more than 20 will be filled on average), or a dynamic class, using DynaBean, Map<String, Object> or something of the sort?
It is better to use class with properties or maybe some composite class which would allow you to limit number of properties in a single class due to composition.
With this approach you (and any other developer) will know exactly which properties and of which types does object have.
If you go with map then you will lose type safety because you will have to use Map<String, Object> to accommodate values of properties of different types. Also with map approach the only way to know which properties exist (which keys are added to the map at runtime) is to debug your code.

Dynamic SQL-Application

I want to create a dynamic sql java application. Normaly i create a java pojo with hard coded columns. For Example:
public class DbEntry{
private int id;
private String name;
public setter and getter
}
Now, the problem is, that the user can change the Database columns as he need. For example, he can add new columns if he need and so on. But if he change the columns the hard coded pojo cant representate the whole db entry. I have read over dynamic byte code creation, but i dont really want to use this, if there is an other/better solution.
Consider this class:
public class DbEntry{
List<Integer> integerList;
List<String> strList;
public Integer getInt(int index){
return integerList.get(index);
}
public String getStr(int index){
return strList.get(index);
}
//todo: add some constructors/factory methods
}
For fixed columns, you can write some global constants like staic int I_ID=0 and static int I_NAME=0. So you can get the id and name of an DbEntry by calling dbEntry.getInt(I_ID) and dbEntry.getStr(I_NAME)
For changeable columns you can use a List<String>, add new column names to the list and then you can call dbEntry.getStr(collst.indexOf("name"))
Or you can write a class using strings as keys, so you can call dbEntry.getStr("name"), e.g.:
public class DbEntry{
Map<String,Integer> integerMap;
Map<String,String> strMap;
public Integer getInt(String key){
return integerMap.get(key);
}
public String getStr(String key){
return strMap.get(key);
}
//todo: add some constructors/factory methods
}
This class looks more straightforward but it wastes some memory. Because every dbEntry in the same table has the same set of column names. A single list is enough for storing the column names of a table. HashMap uses more memory than ArrayList. Despite this disadvantage, what data structures to use still depends on your requirements.
Or you may want to make it an interface with getInt, getStr, getDate, getBlob, so you can have the flexibility by implementing the interface using different data structures.
I have seen this done, and it is a lot of work. What you end up doing is having a dynamic model, typically modelling classes and attributes. You expose the Classes and Attributes (and their definition) to a sysadmin role.
The rest of the application sends and retrieves instance data using this dynamic model. As a start, you won't have static Java classes representing them. In your above example, the DbEntry doesn't exist. You'll end up with a generic Model Object that allows you to return DbEntry objects in a common model. Something like
class DynamicObject {
ClassDefinition getClass(); // a ClassDefinition that contains details about DbEntry
Collection<AttributeDetails> getAttributes();
AttributeValue getValue(AttributeDetails details);
void setValue(AttributeDetails details, AttributeValue value);
}
This above is all bespoke code written/defined by you. I am unaware of any third party framework that provides this to you. That said, I haven't looked very hard.
The bottom line is, for what you want to do, the Classes and Attributes end up being modelled by the application and the rest of the application works off that model. Only by doing that, will you prevent the need for making static Java changes when the model changes.
It is not trivial, and carries with it a fair amount of maintenance. I have seen this done, and over time it did become a fairly arduous task to maintain.

How to dynamically create Lists in java?

I'm programming in java for a class project.
In my project I have airplanes, airports and passengers.
The passenger destination airport is randomly created, but then I have to add it to a List with passengers for that destination.
As long as the airports are read from a file thus they can vary, how can I create Lists according to these airports?
What I want to do is something like:
List<Passenger> passengersToJFK = new ArrayList<Passenger>();
.
.
.
if(passenger.destination == "JFK"){
passengersToJFK.add(passenger);
}
The problem is that as I've said, the number and name of airports can vary, so how can I do a general expression that creates Lists according to the Airports File and then adds passengers to those Lists according to the passenger destination airport?
I can get the number of Airports read from the file and create the same number of Lists, but then how do I give different names to this Lists?
Thanks in advance
You can keep a registry of the associations between a destination or airport and a list of passengers with a Map, in a particular class that centers this passengers management.
Map<String,List<Passenger>> flights = new HashMap<String,List<Passenger>>();
Then, whenever you want to add a new destination you put a new empty list and
public void addDestination(String newDestination) {
flights.put(newDestination, new ArrayList<Passenger>());
}
When you want to add a passenger, you obtain the passenger list based on the destination represented by a String.
public void addPassengerToDestination(String destination, Passenger passenger) {
if(flights.containsKey(destination))
flights.get(destination).add(passenger);
}
I suggest you dig a little deeper into some particular multi-purpose Java classes, such as Lists, Maps and Sets.
I would probably create a Map of airports with airport name as the key and a List of passengers as the value.
e.g.
Map<String, List<String>> airports = new HashMap<String, List<String>>();
airports.put("JFK", passengersToJFK);
You sound like you're thinking too much in terms of primitives, Strings, and collections and not enough in terms of objects.
Java's an object-oriented language; start thinking about Objects and encapsulation.
You've got a good start with your Passenger class. Keep going with Airport.
Do you add Passengers to Airport? Nope, I think they belong to a Flight.
Do a little thinking about your problem before you write more code.
You shouldn't focus on giving the actual variables of list objects unique names, but instead, create a map from String (destination id) to List (passengers heading to that destination), and add lists on the fly to that map, linking each new list to its relevant destination. Update the lists in that map as needed.
The best way to do it is to create objects for all three.
You might have an Airport object that looks like this:
class Airport{
String name;
List Airplane airplanes;
}
then you would have an airplane that looked like this:
class Airplane{
String name; // ?? or bodyType? or whatever else you need
List Passenger passengers;
}
In this way you compose your objects from each other in a way that ends up being much easier to understand and deal with.
Note that I'm leaving off methods, like Airport probably has a method like "addAirplane" to add another airplane, and the airplane object has an addPassenger method...

Vectors in Java, how to return multiple vectors in an object

I'm working on a java program, and I have several vectors defined and filled (from a file) inside a method. I need to return the contents of all the vectors from the method. I have heard you can put them all in one object to return them. Is that possible, and if so, how? If not, do you have any possible solutions for me? Thanks in advance for your help!
Here is a code snippet:
Object getInventory()
{
Vector<String> itemID=new Vector<String>();
Vector<String> itemName=new Vector<String>();
Vector<Integer> pOrdered=new Vector<Integer>();
Vector<Integer> pInStore=new Vector<Integer>();
Vector<Integer> pSold=new Vector<Integer>();
Vector<Double> manufPrice=new Vector<Double>();
Vector<Double> sellingPrice=new Vector<Double>();
Object inventoryItem=new Object(); //object to store vectors in
try
{
Scanner infile= new Scanner(new FileReader("Ch10Ex16Data.txt"));
int i=0;
while (infile.hasNext())
{
itemID.addElement(infile.next());
itemName.addElement(infile.next()+infile.nextLine());
pOrdered.addElement(infile.nextInt());
pInStore.addElement(pOrdered.elementAt(i));
pSold.addElement(0);
manufPrice.addElement(infile.nextDouble());
sellingPrice.addElement(infile.nextDouble());
i++;
}
infile.close();
System.out.println(itemID);
System.out.println(itemName);
System.out.println(pOrdered);
System.out.println(pInStore);
System.out.println(pSold);
System.out.println(manufPrice);
System.out.println(sellingPrice);
}
catch (Exception f)
{
System.out.print(f);
}
return inventoryItem;
}
Personnally, I'd scrap that approach completely. It seems like you need a Product class:
public class Product {
private String itemName;
private int itemID;
// etc etc
public Product(String itemName, int itemID) {
this.itemName = itemName;
this.itemID = itemID;
// etc etc
}
public String getItemName() {
return itemName;
}
public int getItemID() {
return itemID;
}
// etc etc
}
Then something like this :
public class Invertory {
private List<Product> products = new ArrayList<Product>
// etc etc
public Inventory(String fileName) throws IOException {
// Load file,
// Read each product,
products.add(new Product(...product arguments); //add to array
}
public Product[] getProducts() {
return products.toArray(new Product[]{});
}
}
First of all, use ArrayList instead of Vector. Then use a Map as your return object, with each value of the entry is one of your Lists.
Second of all, a much better approach is to create an object that actually holds each of your fields and return a java.util.List of these objects.
public class Item
{
String id;
String name
Integer pOrdered;
Integer inStore;
:
:
You're doing a few things wrong.
Firstly, don't use Vector. Like, ever. If ordering is important to you, you want List on the API (and possibly ArrayList or LinkedList as an implementation).
Secondly, you're trying to have a large number of arrays have values that happen to line up. That's going to be nearly impossible to use. Just create a class that represents one record, and return the List of those.
Thirdly: do not catch that exception. You don't know what to do with it, and you're just going to confuse yourself. Only catch an exception if you have a really good idea what to do in the error case (printing out an error message without a stack is just about never the right thing).
The signature of your method is the most important part. If you get that right, the implementation doesn't matter nearly as much. Aim for something that looks like this:
List<Item> getInventory(File input) throws IOException {
}
You really should reconsider your design here. You have multiple vectors, each with properties of the same type of thing — an item in your inventory. You should probably turn this into a single class, perhaps InventoryItem, with members for the name, price, etc. Then, when reading in each item, you construct an InventoryItem with the given properties, and return a single Vector<InventoryItem>.
If you're really attached to keeping track of all those individual Vectors, you could just return a Vector[] with all the vectors you have:
return new Vector[] { itemID, itemName, pOrdered, pInStore, pSold, manufPrice, sellingPrice };
Also, as Robin says, you should use the ArrayList container instead of Vector. The only thing that will change is that you need to change all calls to someVector.AddElement to someList.add.
Sounds like this should be tagged "Homework".
Okay, first of all, are you required to use all these Vectors, or is that your own decision? Though some may point out that using ArrayLists is better, I'd do away with them and create your own Item class.
This way, instead of having a conceptual item's properties distributed across multiple Vectors (the way you're doing now) you have 1 Item instance per item, with fields for all the data relevant to that item. Now, you only need one data structure (Vector or ArrayList) for all your item objects, and you can return that structure from getInventory().
The easiest way to declare the object would be something like
List<Vector<? extends Object>> inventoryItem = new ArrayList<Vector<? extends Object>>
but this has several problems, namely that Java's generics aren't reified, so you have to test and cast the contents of each vector that you get back. A better solution would be to define a container object that has each of the Vectors as fields and add to those.
However, this looks like it is really missing the point. Instead, you should define an InventoryItem who has each of your seven fields. Each time you read an object from the file, instantiate a new InventoryItem and populate its fields. Then, you add this to a single Vector.
Also, it is generally recommended that you do not use the Vector class. Instead, you should use ArrayList. Vector should really only be used if you need its synchronization properties, and even then you should consider wrapping some other list in a Collections.synchronizedList().
Finally, the places where you would want to catch just an Exception can be counted on one hand. You should really be catching an IOException and even that you might want to consider just rethrowing. Also, you should call printStackTrace() on the exception rather than System.out.println().
I find that a good rule of thumb is that it's never really a good idea to pass collections around outside your objects. They are obviously useful inside your object, but outside you lose control and they are not obvious.
Consider the principle of making your code readable instead of documenting it. If you take a collection, how does that tell the caller what to pass in? Even if you use generics, there is no way to assert control over what happens to the collection--someone could be adding to it and deleting from it in another thread after it's passed to you.
There is no reason not to create a business class that contains your collections along with the business logic to manipulate them (yeah, there is always business logic--it's the copy and paste code you'll find around the locations that you access the collection).
I used to find it frustrating that the JDK always seems to take arrays of built-in types rather than collections, but it makes a lot more sense after coming to terms with the idea that passing collections (like passing around any basic type) is just not a very good idea.
While in general I heartily agree with the advice to use List/ArrayList instead of Vector, it is important to know why. Indeed, I have to vehemently disagree with Dustin who says not to use Vector "ever".
A Vector is in essence a synchronized ArrayList. If you truly need synchronization, by all means then, ignore Dustin's admonition, and use Vector.
There is another instance in which Vector is justified. And that is when you need to maintain compatibility with a pre-Java2 code base.

Categories