Array vs. ArrayList when position is important - java

I'm a Java newbie with a quick Array vs. ArrayList question. I have an array of objects that can grow or reduce in size, but it's very important for me to maintain the position they were in relative to each other in the array. I'm thinking because of this I need to use Array instead of an ArrayList which can condense/shift elements around if they are removed/added.
The practical example: In my first Java application that I'm slugging through to learn the nuances of this language I'm making a basic poker game simulator. I have Player objects in an array representing the seats they are sitting at, and it's important to know where the dealer button (index) was placed before rotating it. Players being removed or added from an ArrayList will change the indices of the players, and that can throw off the next Player to get it. Dealer button movement is very player-placement specific.
Long story short - is using an Array the best way of handling elements in an array-type structure that need to maintain their position in the array? Is there a better method or logic to accomplish this? I apologize for the simple question but I couldn't find any other alternatives and wanted to confirm that this is the best route to take.
EDIT:
To further clarify, let me give an example of why ArrayList's element movement won't work:
Take three players and their indices in the array:
0 : Player One (Dealer button)
1: Player Two
2: Player Three
If player two (index one) gets up from the table before the dealer button is rotated, depending on the rules player one will keep the button and the blinds will be adjusted accordingly (there's other variants of this rule, but the one I like to use). In an ArrayList, the internal array will be condensed and player three will end up getting the button an extra round before he should. I need to track the empty seat that was active during the hand but was emptied before the round was over and the button moved.
I'm starting to realize that the concept of a "seat" is going to be more complicated, I need to track state on it, including "player just sat down while hand in progress," "player got up while hand in progress," etc. #Stephen P - I think you're right about this, I'm going to need to track them separately and cannot use a simple array structure to determine the logic. Timing of when the elements are added and/or removed is paramount to the application logic, and simply examining if an element is there or not won't cut it.
For the Seats themselves, I'm learning towards ArrayList since the Seats will now always be there, no empties. The Seat will just have a reference to the Player object if one is sitting there as well as WHEN that player arrived. Thanks everyone!

With ArrayList, you can make your players sit tight by using set(int index, T value). You just have to fill the arrayList with nulls first:
List<Player> seats = new ArrayList<>(Collections.nCopies(numPlayers,(Player)null));
seats.set(2,player); // Place a player in the third chair
seats.set(1,null); // Empty the second chair

Long story short - is using an Array the best way of handling elements
in an array-type structure that need to maintain their position in the
array? Is there a better method or logic to accomplish this? I
apologize for the simple question but I couldn't find any other
alternatives and wanted to confirm that this is the best route to
take.
Position shouldn't be your most important criterion for choosing array vs. ArrayList, at least I don't believe it should be.
Arrays are covariant, and more performant most of the time. They mix poorly (if at all) with Java generics which is really kind of a big deal a lot of the time. You cannot create a reference to a new instance of an array of a non-reifiable type (though you can receive one, but buyer beware).
ArrayLists, as a part of the Java Collections API, are invariant. For this reason they work much better with Java generics and, according to Joshua Bloch (Essential Java, 2nd Ed), should be favored much of the time. ArrayLists should often be less performant (and less concise) than arrays. Moreover, as part of the Java Collections API, ArrayLists are more flexible because they extend the List interface which enables you to change implementations from ArrayList to any other List provided that your own class that implements the List is well encapsulated (i.e. the ArrayList is not part of your class's exported API).
There are other differences, of course, but these are the ones that really stand out. If you were really concerned about performance, you could create your own List implementation that was backed by arrays (like ArrayList is) in order to get a feature or the API contract you really wanted. Otherwise, to me, it sounds like you should be using ArrayList (or even other Collection type such as Map (suggested)).

If you have a constant number of seats, you can use either an array or an ArrayAist. If you want to increase the number of seats, you will need an Arraylist, because regular arrays are immutable. See this for more information on the immutability of arrays: Why is an array's length immutable? An ArrayList will never move around its contents if you only use the get(int index) and set(int index, E element)
Also, it is bad practice to let null mean something, even if that something is nothing.
The code:
seat ArrayList initialization
List<Person> seats = new ArrayList<Person>(max_Number_Of_Seats_here);
for(Person person : seats)
{
person = new Person("");
}
//You can then set people like this:
seats.set(seat_index_here, new Person("Darkprozac"));
And have the parameter for the constructor for the class Person be its name.
Person constructor
...
public String name;
public Person(String name)
{
this.name = name;
...
You can then check if the Person's name is "", and if it is, skip that person:
Check if seat is empty
...
for(Person person : seats)
{
if(person.name.equals(""))
{
//do nothing
}
else
{
doSomething();
}
}
...
You can also wrap a Person in a Seat class:
Seat Class
public class Seat
{
public Person person;
public String state;
public Seat(String name)
{
if(name.equals("");
{
state = "empty";
}
else
{
state = "full";
person = new Person(name);
}
}
}
and then modify seat ArrayList initialization and Check if seat is empty accordingly.
Thanks to MrBackend for pointing out that I was wrong about ArrayLists initializing as null.

I would use a map, specifically, a TreeMap.
NavigableMap<Integer, Player> seats = new TreeMap<Integer, Player>();
Integer first = seats.firstKey();
Integer next = seats.nextKey(first);
This gives the benefits of a map, you don't have to worry about seats shifting (even accidentally), and you can still navigate seats easily.
The map manages its own storage (unlike an array) and does not have a risk of shifting indices (unlike an ArrayList).

Related

Good practice to avoid ConcurrentModification of static collection

Consider class of Player... when player joins the game (object is created), it checks for player with the same name already joined...
public class Player {
private static List<Player> players = new ArrayList<>();
private String name;
public Player(String name) {
this.name = name;
for (Player otherPlayer : players) { // Iterating static field
if (otherPlayer.name.equalsIgnoreCase(name)) {
otherPlayer.quit("Somebody with the same name joined the game");
}
}
}
public void quit(String message) {
players.remove(this); // Modifying static field
Server.disconnect(this, message);
}
}
I know that Iterator can deal with this problem, but we don't always know what happens with public static fields in foreign methods and when to use foreach and when to use Iterator instead...
Is there any good practice for this problem?
The first, and more important good practice is called separation of concerns. As in: the Player class should model a single player.
You are mixing the responsibility of being a Player and managing the overall set of Player objects in one place. Don't do that!
These two things simply don't belong together. In that sense: there should be a PlayerManager class for example that knows about all players. And also forget about using a static field like this. Because that creates super-tight coupling between the different aspects of your class. What happens for example when you need more than one list of players? What if you have so many players that you want to organize them in buckets, based on certain properties?
Beyond that, the direct answer is: instead of immediately deleting objects from your list - collect them into a second playersToBeDeleted list. And after iterating the first list, simply use players.removeAll(playersToBeDeleted) for example.
And talking about good practices: carefully consider if you really want to use Lists - or if Set wouldn't be the better alternative. Lists always imply order, and yuck, they allow to repeatedly add the same object. Whereas a Set gives you "unique elements" semantics for free!
I see that you are trying to call list.remove(entry) method while still inside the for-each block. Don't do that.
Use Iterator instead of the for-each construct when you need to:
Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.

Checking availability

Let's say I'm running a book store and someone placed an order for a list of books. B,C,D,A,A,A (the parameter)
I need to return true if all of those books are found in my inventory array. If there are two instances of the same book in the list being passed in (in this case A), I need to check to see if there are that many instances of that book in my inventory. I'm traversing through both the parameter array and the inventory array but as of now my code is returning true even if there's only one A book in my inventory. I am stuck on the logic of writing code that checks to see that there are 3 A books in my inventory. In essence, the customer is placing an order and I need to tell them if I have the books he wants. The order list will be arranged in descending order of retail value. So all three A books will be right next to each other if that makes it easier.
Here is the skeleton of what I have so far.
public boolean checkAvailability(customersOrder listToCheck) {
for(int i = 0; i<listToCheck.items.length; i++){ //listToCheck's items array
for(int j = 0; j<items.length; j++){ //inventory array
if(listToCheck.items[i].equals(items[j])){
return true;
}
}
}
return false;
}
This is very dependent on how you are storing your data, the simplest and most generic way that will work with virtually all data designs though is:
Sort your array before processing it, this will group all identical books together.
Now when you look to see whether you have enough books you can check there are enough to cover every instance of that book within the order.
As this looks like homework (too simple restrictive datastructures), just an idea
Walk the listToCheck
For the ith element, say A we handle all As
If it occurs before i too, skip (you handled it already)
Count the same items >= i: `quantity`
Loop the stock to find `#quantity` items.
If after the loop #quantity not reached, return failure
If after the walk of listToCheck reached
return success
If the same items appear one after another the quantity can be determined simply, and the loop becomes simpler.

Creating pointers out of HashMap objects in an object array

This is sort of an follow up to the first post I made, lets say I got two classes:
public class Carinfo {
private String carname;
//The Carinfo[] value is set when making a new car
//so for the object ford the array holds 3 null pointers
private Carinfo [] value;
Carinfo (String someCar, int carValue) {
this.carname = someCar;
this.value = new Carinfo[carValue];
}
}
And the second class:
public class CarPark {
HashMap<String, Carinfo> carGarage;
CarPark() {
carGarage = new HashMap<String, CarInfo>();
Carinfo ford = new Carinfo("Ford", 3);
Carinfo audi = new Carinfo("Audi", 2);
carGarage.put("Ford", ford);
carGarage.put("Audi", audi);
}
}
So let's say for whatever reason I want the object ford who has 3 null pointers
in its Carinfo array, to point at the object audi.
Meaning I can go through the Carinfo objects and list the pointers each car
has to other cars.
Think of it as a family, I want to see what cars are related to each other.
I am having a hard time creating a method that will point to other objects
in my Carinfo HashMap.
Any "pointers"? If anything is unclear please let me rephrase or try to explain it better.
Cheers
I don't really understand what you're trying to do. One way to realize that is to provide a specific method to add a relation. For example, with your array you could do that:
public class CarInfo {
private Carinfo[] value;
public void addCarInfo(CarInfo carInfo, int position) {
value[position] = carInfo;
}
}
Anyway, it is not a good idea to have an array, you should use a List.
I would recommend not storing the relationships between cars inside the Carinfo objects themselves. Instead, you should use a general-purpose graph library (or write your own general-purpose graph library).
As you probably know, a graph is a set of nodes and edges, and each edge represents a relationship between two nodes. The notion that your current code describes is really just a directed graph: each car is a node, and each car can hold some number of references to the other cars, where each reference represents an edge pointing out from that car.
Graphs are such a common abstraction in math and computer science that plenty of libraries have been implemented to represent graphs, with the side benefit that several popular problems are solved for any code that uses the libraries (for instance, finding a multistep relationship between two cars using the fewest number of edges, or finding the smallest number of edges needed in the graph to ensure that all the cars are still indirectly connected). I would recommend searching for already-implemented graph libraries, and then using the one with the best features for your overall problem. If this is a homework assignment, though, you should probably implement your own graph library. This isn't too hard: you need to store nodes and edges somehow (you can just keep a list of nodes, and you could use an edge list or adjacency matrix to store edges), and you will need to provide the algorithms you care about in a somewhat more general form. This may seem like more work, but the benefits of making your code more modular will pay off quickly. You'll create fewer bugs in the first place, since each part of your code performs only one job, and you'll be able to fix bugs more easily and quickly, probably saving you time overall.
For starters you'll need accessing methods on your CarInfo object in order to play with the value array you've set up.
public CarInfo[] getCarValue() {
return value;
}
Now, when you're playing in a method you can call it as follows:
CarInfo[] fordValueArray = carGarage.get("Ford").getCarValue();
This array now points to the one you created on the 3rd command of CarPark().
With that we can do:
fordValueArray[0] = audi;
Now, that all said, it seems a little unclear why you'd set up a class relation like this. The naming of value is seemingly non-intuitive because at face value what you've asked is how we can have a car's value relate to a number of other cars independantly. Ford's first value is an Audi? What are the other two values? Why would we be limited to 3 at all?

How to sort 3 parallel arrays?

I currently have 3 arrays of information and am unsure of how to sort them based on one of the values:
int[] rank = { 1, 3, 4, 2, 5 };
String[] game = { "Snake", "Mines", "Fragged", "Siege", "Tower" };
int[] year = { 1980, 1983, 1981, 1995, 1992 };
I'm wanting to sort it by rank, and I've seen many examples of people using comparators to sort 2 parallel arrays, but I haven't seen any example for sorting more than 2.
My first thought was to create a class with a variable for each and then sort that object, but is an extra class really necessary for a sort?
My first thought was to create a class with a variable for each and then sort that object, but is an extra class really necessary for a sort?
It's not strictly necessary - you could definitely write some code to avoid it if you really wanted to. However, I'd say it's a thoroughly good thing.
You don't really have three collections of separate items here: you have one collection of items, each of which has three properties. So make your code match that. Whenever you find you have parallel collections, such that a[0] is related to b[0] is related to c[0] etc, you should think about encapsulating that information in a separate class. It will make your code much easier to maintain, and enforces more consistency.
For example, it would make no sense for those arrays to have different lengths: but there's nothing inherent in the declaration to stop that. If you have one collection, you can't possibly have different numbers of items for the different properties, precisely because you've got one collection.
I think creating a new class would be the cleanest solution. You could manually implement a new sort function to duplicate swaps to the other 2 arrays whenever you apply a swap to the first array (rank), but that gets messy very quickly.
Something like the following would be all you need:
public class Game implements Comparable<Game>{
private int rank = 0;
private int year = 0;
private String name = "";
...
// Constructor +
// Usual getters and setters here
..
public int compareTo(Game anotherGame) {
return this.rank - anotherGame.getRank();
}
}
And then you can simply do:
List<Game> games = new ArrayList<Game>();
...
// Add some games to your games list
...
Collections.sort(games);
Is the extra class necessary? Well no, of course not. You could come up with a sorting routine that would keep everything consistent. However, what happens if next week you decide you need a 4th array, such as a publisher? Now your sorting routine won't work and you have to write a new one.
If you instead write a class to hold these fields as properties, you can simplify the sorting logic immensely, plus you only have to worry about one array. Any extra work you do now will be recouped very quickly then next time you have to maintain this code.

Which Array To Use?

I am designing a new cinema booking system, where there will be 4 screens holding various number of seats on each.
I need to know what ARRAY or what data structure is best for ADDING and REMOVING people onto or off seats ANYWHERE they want on the screen.
I believe that I will need a 2 dimentional array structure, but any help will be much appreciated!... thank you
What you should do is build a class structure that will abstract out the way you are storing the data in memory. You might do something like:
class Cinema {
List<Auditorium> screens;
}
class Auditorium {
int number;
List<SeatRow> rows;
}
class SeatRow {
int rowNumber
List<Seat> seats;
}
class Seat {
int seatNumber;
boolean occupied;
}
Note: This isn't the only solution. You may want to look into storing Seats in a Map or some other data structure.
ArrayList is a nice simple array type list that permits adding and removing.
You could create an array of arrays if you like. That would be a 2 dimentional array.
Sounds like 4 instances of the same data structure. Possibly a Collection of Screen objects that contain a Collection of seats.
I'd vote personally for a plain and simple Seat[][] array of the class structure suggested above. There's simply no reason to use another array as the array size probably isn't ever going to change, if it is that can be done at initialisation. Then just show them or don't on the screen by either data in a certain position or null for unreserved seats.
Depending on your need (do you need to remember where the guest booked?) you could even use boolean[][] as the bare minimum.
No matter what, just create and name four different such Seat 2D arrays. Preferably stick them in a separate class and have setters and getters.

Categories

Resources