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.
Related
I have a class which always holds four objects:
class Foo<E> {
Cow<E> a, b, c, d;
}
I want to be able to iterate over them, so ideally I'd like to use an array:
class Foo<E> {
Cow<E>[] cows = new Cow<E>[4]; // won't work, can't create generic array
}
I don't want to use a list or a set since I want there to always be 4 Cow objects. What's the best solution for me?
If you want to preserve the genericity, you will have to reimplement something similar to a list and I don't think it is worth it.
You said:
The first is that you can add and remove elements to and from a list.
Well you can create an unmodifiable list:
List<E> list = Collections.unmodifiableList(Arrays.asList(a, b, c, d));
The second is that I'm creating a quadtree data structure and using a list wouldn't be too good for performance. Quadtrees have a lot of quadrants and using lists would decrease performance significantly.
First you can initialise the list to the right size:
List<E> list = new ArrayList<>(4);
Once you have done that, the list will only use a little bit more memory than an array (probably 8 bytes: 4 byte for the backing array reference and another 4 byte for the size).
And in terms of performance an ArrayList performs almost as good as an array.
Bottom line: I would start by using a list and measure the performance. If it is not good enough AND it is due to using a list instead of an array, then you will have to adapt your design - but I doubt that this will be your main issue.
Use a generic ArrayList and simply have methods to insert values into your object, and do checks inside those methods, to make sure you don't end up having more than 4 Cow objects.
I will suggest creating a bounded list. Java does not have an inbuilt one however you can create a custom one using Google collections or use the one in Apache collections. See Is there a bounded non-blocking Collection in Java?
Use Collection instead of array:
List<Cow<E>> cows = new ArrayList<>(); // in Java 7
Or
List<Cow<E>> cows = new ArrayList<Cow<E>>(); //Java 6 and below
More information will show why it is IMPOSSIBLE to have arrays whit generics. You can see here
Cow<E>[] cows = (Cow<E>[])new Cow[4];
or
Cow<E>[] cows = (Cow<E>[])new Cow<?>[4];
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).
How do I compare each element in two different sets of data, and then merge certain elements of them into a new set of data?
Some info about my methods below. Note:
Not using java.lang.Collections
In one class I have these calls initializers:
BookCollection collection1 = new BookCollection(100);
BookCollection collection2 = new BookCollection(50);
BookCollection collection3 = new BookCollection(150);
And this call to my method merge(which I am trying to complete)
collection3.merge(collection1, collection2);
Anndd in another class my method merge is trying to compare the two sets of data(collection 1 and 2) and if it finds an elements that are equal, only add 1 of those elements to the new collection. Otherwise, add all of the non-equal elements to the new collection.
Here is what I made, but I know that it isn't working. There is a call to one of my other methods findBook that I will post.
public BookCollection merge(BookCollection c1,BookCollection c2){
//use this. operator to grab other vars
BookCollection cNew = new BookCollection(cNew);
for(String s1: c1)
if (s1.equals(c2)) {
cNew = c1;
}
cNew = c1 + s1;
}
Annddd
private int findBook(String isbn){
// iterate all the Book elements in the collection array
for(int i = 0; i <= collection.length; i++){
// check if the current book isbn matches the one provided argument
if (collection[i].getIsbn().equals(isbn))
return i;
}
return -1;
}
The solution should be far shorter than that.
I'll give you some tips because the idea is not give plain solutions and this question I'm pretty sure is homework.
If the question is homework add 'homework' tag
Tips:
Your main method doesn't have any loop. How are gonna iterate over the collections?
Books as objects they are should have an equals method. If that method is correctly implemented (you should define what is a method begin equals to another), then you just can compare b1.equals(b2)
Collections have contains method to check if it contains (by using equals) other book
Math.min method calculates the minimum between two integers or doubles (there are two versions)
Also, to be complete, if your collections are of a certain type your books should implement hashCode in a compatible way with equals (but my guess is you don't know what hashing is yet, and you'll not use that kind of collections)
So first of all: devise an algorithm. The simpler the better. In plain English.
Just then try to implement that. You'll see the code is much simpler and tidy if you try to program a previous well thought concept.
Edit:
Ensure to know what a Collection is in Java world (tip: is a general interface implemented by several distinct more specific classes).
And don't use the word array unless you are using real arrays (and given your exercise proposal it doesn't seem you need it).
Well , I'm stock on something very simple but I can't figure it out.
First off, I know that there is Collection.sort() method, but my ArrayList is sort of links to data to main object, and my sorting is needed to be made according to this object's data.
Like this is a sport competition and ArrayList<Integer> numbers is keeping numbers of participants that has passed a checkpoint.
And I need to sort this ArrayList by the best time from min to max to set them on who's on 1st place, 2nd etc.
for this I should ask my Competiton object :
public ArrayList<Integer> sort (ArrayList<Integer> numbers)
for (int i=0;i<numbers.size){
long time = competition.participant.get(numbers.get(i)).getTimeOfLastCheckPoint();
/*Do something to make another ArrayList<Integer> sortedArray
where all this will be sorted by this time parameter from minimal to maximum*/
return sortedArray;
}
this is not the actual code, but you've got the idea. I stuck with trying to find seemingly easy solution.
Please Help
It seems awkward to sort an ArrayList<Integer> based on other things that have nothing directly to do with what you actually want to sort on -- the times.
I would design it differently. It looks you have some kind of object defined on which you can call getTimeOfLastCheckPoint(). For now, I'm assuming it's called Participant. Instead of maintaining an ArrayList<Integer> to store index-based references to your participants, I would maintain an ArrayList<Participant>.
Then I would create a class that implements Comparator<Participant> (perhaps ParticipantComparator) (Comparator javadocs) that knows how to compare Participants based on the results of the call to getTimeOfLastCheckPoint(). Then sorting is simply Collections.sort(participantsArrayList, new ParticipantComparator());.
Write a java.util.Comparator that compares Integers by using them as index in your participants-array:
public class ParticipantIndexComparator implements Comparator<Integer> {
final List<Participant> participants;
public ParticipantIndexComparator(List<Participant> participants) {
this.participants = participants;
}
#Override
public int compare(Integer i1, Integer i2) {
long l1 = participants.get(i1).getTimeOfLastCheckPoint();
long l2 = participants.get(i2).getTimeOfLastCheckPoint();
return Long.compare(l1, l2);
}
}
Now you can use this comparator to sort your integers:
Collections.sort(numbers, new ParticipantIndexComparator(participants));
But before doing so, ask yourself why your list contains Integer-objects that are indices to the participants-list, instead of the Participants themselves!
For me, this sounds like a workaround solution for a half-done SQL query. In case that your data resides in a data base (and I'm pretty sure that this is the case), modify your SQL- query so that you don't have to do that sorting of data at application level. This is good for at least two reasons:
Simplyfiy application logic
Speed up execution (The data base can do such sorting much faster)
You can use a Comparator to sort the list according to their race duration and also use for-each loop in Java.
I have to refactor an existing project, which is not that small. It contains a lot of arrays declarations and accesses:
(X is not a generic type, it's just a placeholder).
declarations: X[] and X[][],
access: someArray[i] and someArray[i][j].
I have to rewrite everything to use generic Lists:
declaration: List<X> and List<List<X>>,
access: someList.get(i) and someList.get(i).get(j).
I couldn't find a possibility to automatize such refactoring, neither in Eclipse, nor in Netbeans (both newest versions).
Are there some tools available to do such refactoring?
EDIT:
The project is very algorithm-oriented. Internal implementation of algorithms will not be touched. But the exposure to the external world must be changed. Most classes are made in such a way, that they only hold some result arrays or arrays of arrays.
exposure to the external world must be changed
In that case I'd avise not to change it everywhere, but to :
change only return types of the public methods
write an utility method, which looks like:
public static List<List<X>> asList(X[][] x) {
List<X[]> list = Arrays.asList(x);
List<List<X>> newList = new ArrayList<List<X>>(list.size());
for (X[] xArray : list) {
newList.add(Arrays.asList(xArray));
}
return list;
}
use that method to change the only result of each public method. I.e.
public List<List<X>> someAlgorithm(...) {
// algorithm code
X[][] result = ...;
return Utils.asList(result); // add only this line
}
I can hardly agree that things you are going to do could be called 'refactoring'.
Arrays has some possibilities that lists don't have (and of course vise versa).
For example, if you create new array of 10 integer elements then its size is 10, and it has ten zero values.
You can also use its index in some tricky way. For example, think about radix sort algorithm. To implement it with lists you should first add a lot of zeros to this list and you'll get twice worse performance.
I'm telling this to explain the idea that it's almost impossible to implement robust tool for doing what you want to do.