Folks, my method needs to add a new element into already a sorted list, i.e. in a proper position. The point is the method checks the lowest row index and then compares its cols. For example,
board.set(2,2, 11);
board.set(-1,0,22);
board.set(-1,2,33);
board.set(1,0,44);
board.set(3,0,55);
board.set(3,1,66);
board.set(3,3,77);
board.set(3,2,88);
board.set(-1,1,99);
The result should be:
[(-1,0,22), (-1,1,99), (-1,2,33), (1,0,44), (2,2,11), (3,0,55), (3,1,66), (3,2,88), (3,3,77)]
But my program prints this:
[(-1,0,22), (-1,1,99), (3,2,88), (3,3,77), (3,1,66), (3,0,55), (1,0,44), (-1,2,33), (2,2,11)]
i.e. it does not put the objects into the proper positions.
I have a LinkedList<RowColElem<T>>rowColSeq where the objects are added and put into a proper position "on the go". What is my code missing?
NOTE: Im not allowed to use comparators, comparable interface!
LinkedList<RowColElem<T>> rowColSeq; // Is not empty, already contains objects!
private void sortedRowColSeq(int row, int col, T x){
RowColElem<T> object = new RowColElem<T>(row, col, x);
ListIterator<RowColElem<T>> iter = rowColSeq.listIterator();
RowColElem<T> inListObject;
boolean added = false;
while(iter.hasNext()){
inListObject = iter.next();
if(object.getRow() < inListObject.getRow()){
iter.previous();
iter.add(object);
undoStack.push(object);
added = true;
break;
}
else if(object.getRow() == inListObject.getRow()){
if(object.getCol() < inListObject.getCol()){
iter.previous();
iter.add(object);
undoStack.push(object);
added = true;
}
}
else{
iter.add(object);
undoStack.push(object);
added = true;
break;
}
}
}
You may not add if the new element is greater than some element. You must enter before one that is greater, or at the end.
boolean added = false;
while(iter.hasNext()){
inListObject = iter.next();
if(object.getRow() < inListObject.getRow() ||
object.getRow() == inListObject.getRow()) &&
object.getCol() < inListObject.getCol() ){
if( iter.hasPrevious() ){
iter.previous();
iter.add(object);
} else {
rowColSeq.addFirst( object );
}
undoStack.push(object);
added = true;
break;
}
}
if( ! added ){
rowColSeq.addLast(object);
undoStack.push(object);
added = true;
}
The approach using iter.previous() is doomed to fail under certain circumstances so I added a test and alternative code.
Related
I'm currently doing an assignment which requires me to use classes to make an album collection manager. I've been debugging and came across a problem. The Album[] is supposed to hold all the Album objects while numAlbums is supposed to keep track of the number of albums, but when I run the add method, it will increment the numAlbums and add the album to Album[], but once the method ends, it will reset instead of staying where it should be.
This is a problem especially since I can't print the album list since it relies on the numAlbums incrementing in value.
public class Collection {
private Album[] albums;
private int numAlbums; //number of albums currently in the collection
//find the album index, or return NOT_FOUND
private int find(Album album)
{
String title = album.getTitle(); // First, put the title and artist in string variables.
String artist = album.getArtist();
for (int i = 0; i < albums.length; i++) // Let's find this album.
{
Album c = new Album(); // Make Album c so we can compare every album.
c = albums[i];
if (title == c.getTitle() && artist == c.getArtist()) // If the title and artist match, then return the index.
{
return i; // We found the album!
}
}
return -1; // Album doesn't exist.
}
//increase the capacity of the array list by 4
private void grow()
{
Album[] temp = new Album[getAlbums() + 4]; // Create new temp array with 4 more spaces.
for (int i = 0; i < albums.length; i++) // Use loop to insert all values from albums to temp.
{
temp[i] = albums[i];
}
albums = temp; // Overwrite previous albums with new one.
}
// Add an Album. Command A.
public boolean add(Album album)
{
int counter = 1;
if (getAlbums() == 0) // If there are no albums, grow the list to the first 4 indexes.
{
Album[] temp = new Album[numAlbums + 4];
albums = temp;
}
else if (getAlbums() > 0)
{
Album search = new Album();
for (int i = 0; i < albums.length; i++) // Check if the album has the same title and artist in the collection.
{
search = albums[i];
if (album.getTitle().equals(search.getTitle()) && album.getArtist().equals(search.getArtist()) == true)
{
return false;
}
}
}
int a = getAlbums();
albums[a] = album; // Put the album in the collection.
a++; // Increase the amount of albums.
setAlbums(a);
if (numAlbums == 4 * counter) // If the number of albums reach multiples of 4, then increase the array and counter.
{
grow();
counter++;
}
for (int i = 0; i < albums.length; i++)
{
System.out.println(albums[i]); // Simple print of the list.
}
return true;
}
// Remove an Album. Command D.
public boolean remove(Album album)
{
if (find(album) == -1) // First, find the album to remove.
{
return false; // That album does not exist.
}
else // The album exists.
{
int index = find(album); // Copy the index number.
for (int i = index; i < albums.length; i++)
{
albums[i] = albums[i + 1]; // Shift the elements to the left by 1.
}
}
int a = getAlbums();
a--; // Decrease the amount of albums.
setAlbums(a);
return true; // We removed it.
}
//set to not available. Command L.
public boolean lendingOut(Album album)
{
if (find(album) == -1) // First, find the album to lend.
{
return false; // That album does not exist.
}
else // The album exists.
{
if (album.isAvailable() == false)
{
return false;
}
else
{
album.setAvailable(false);
}
}
return true; // We removed it.
}
//set to available. Command R.
public boolean returnAlbum(Album album)
{
if (find(album) == -1) // First, find the album to lend.
{
return false; // That album does not exist.
}
else // The album exists.
{
if (album.isAvailable() == true)
{
return false;
}
else
{
album.setAvailable(true);
}
}
return true; // We removed it.
}
//display the list without specifying the order. Command P.
public void print()
{
int y = getAlbums();
if (y == 0) // If the collection is empty, then return empty.
{
System.out.println("The collection is empty!");
return;
}
for (int i = 0; i < albums.length; i++)
{
System.out.println(albums[i]); // Simple print of the list.
}
}
//display the list sorted by the release date. Command PD.
public void printByReleaseDate()
{
if (getAlbums() == 0) // If the collection is empty, then return empty.
{
System.out.println("The collection is empty!");
return;
}
Album[] SortAlbumsRelease = new Album[numAlbums]; // Make another array to store the album list order.
for (int i = 0; i < albums.length; i++)
{
SortAlbumsRelease[i] = albums[i]; // Copy the contents of the array.
}
Album First = new Album(); // Create temp albums so we can compare.
Album Second = new Album();
Album temp = new Album();
for (int o = 0; o < albums.length; o++) // Go through every single album.
{
for (int p = 0 + 1; p < albums.length; p++)
{
First = SortAlbumsRelease[o];
Second = SortAlbumsRelease[p];
int compare = First.getReleaseDate().compareTo(Second.getReleaseDate()); // Use the compare method from date to get a value.
if (compare == -1) // If the first value is lower, then put that album in the previous slot.
{
temp = SortAlbumsRelease[o];
SortAlbumsRelease[o] = SortAlbumsRelease[p];
SortAlbumsRelease[p] = temp;
}
}
}
for (int i = 0; i < albums.length; i++) // Print the list.
{
System.out.println(SortAlbumsRelease[i]);
}
}
//display the list sorted by the genres. Command PG.
public void printByGenre()
{
if (getAlbums() == 0) // If the collection is empty, then return empty.
{
System.out.println("The collection is empty!");
return;
}
Genre type = null; // Set the genre type.
Album Temp = new Album(); // Make a temp album.
for (int i = 0; i <= 4; i++) // Iterate through all the genre cases.
{
switch(i)
{
case 0:
type = Genre.Classical;
case 1:
type = Genre.Country;
case 2:
type = Genre.Jazz;
case 3:
type = Genre.Pop;
case 4:
type = Genre.Unknown;
}
for (int j = 0; j < albums.length; j++) // Look through the albums that have the matching genre.
{
Temp = albums[j];
if (Temp.getGenre() == type) // If they match, print in that order.
{
System.out.println(albums[j]);
}
}
}
}
public int getAlbums()
{
return numAlbums;
}
public void setAlbums(int m)
{
numAlbums = m;
}
}
Below is the manager we have to create when running the program. We also use an album, genre, and date class, but I feel like the problem is somewhere in these areas.
import java.util.Scanner;
public class CollectionManager
{
public void run()
{
System.out.println("Collection Manager starts running."); // Begin.
while(true)
{
Scanner input = new Scanner(System.in);
String collect = input.nextLine(); // Take the input in.
String[] output = collect.split(","); // Creates an array "output" and splits the input by commas.
// Below is the designated spots for array "output" after the split.
// A,Change,Anika,pop,7/23/2021
//[0] [1] [2] [3] [4]
switch(output[0])
{
case "A": // Add the album.
Album a = new Album();
if (a.MakeAlbum(output) == true) // If the output goes well and returns true, then add to the collection.
{
Collection add = new Collection();
if (add.add(a) == true) // If true, add the album.
{
System.out.println(a + " >> added.");
break;
}
else // Otherwise, it's already in there.
{
System.out.println(a + "is already in the collection.");
break;
}
}
else // If the date is invalid, then return Invalid Date!
{
System.out.println("Invalid Date!");
break;
}
case "D": // Delete an Album.
Album d = new Album();
d.MakeAlbum(output);
Collection delete = new Collection();
if (delete.remove(d) == true) // If the album is in the collection, delete.
{
System.out.println(d.getTitle() + "::" + d.getArtist() + " >> deleted.");
break;
}
else // Otherwise, it doesn't exist.
{
System.out.println(d.getTitle() + "::" + d.getArtist() + " >> is not in the collection.");
break;
}
case "L": // Lend an Album.
Album l = new Album();
l.MakeAlbum(output);
Collection lend = new Collection();
if (lend.lendingOut(l) == true) // If the album is in the collection, lend.
{
System.out.println(l.getTitle() + "::" + l.getArtist() + " >> lending out and set to not available.");
break;
}
else // Otherwise, it doesn't exist or can't be lend out.
{
System.out.println(l.getTitle() + "::" + l.getArtist() + " >> is not available.");
break;
}
case "R": // Return the album.
Album r = new Album();
r.MakeAlbum(output);
Collection ret = new Collection();
if (ret.returnAlbum(r) == true) // If the album is in the collection, return.
{
System.out.println(r.getTitle() + "::" + r.getArtist() + " >> returning and set to available.");
break;
}
else // Otherwise, it doesn't exist or can't be returned.
{
System.out.println(r.getTitle() + "::" + r.getArtist() + " return cannot be completed.");
break;
}
case "P": // Print with no order.
Collection Print = new Collection();
Print.print(); // Print the album list.
break;
case "PD": // Print with release date order.
Collection PrintD = new Collection();
PrintD.printByReleaseDate();; // Print the album list by release date.
break;
case "PG": // Print with genre order.
Collection PrintG = new Collection();
PrintG.printByGenre(); // Print the album list by genre.
break;
case "Q": // Quit the program.
System.out.println("Collection Manager terminated.");
return; // The end.
default: // Invalid. Try again.
System.out.println("Invalid command!");
break;
}
}
}
}
I can't find anything on google relating to the problem so any help is appreciated.
The problem is that you're creating a new collection object per switch statement. Instead, create the object prior to your while loop.
//initialize collection object prior to while loop
Collection myCollection = new Collection();
while(true){
Scanner input = new Scanner(System.in);
String collect = input.nextLine();
String[] output = collect.split(",");
switch(output[0]){
case "A":
Album a = new Album();
if(a.MakeAlbum(output) == true)
{
//adding to the same collection object created previously
if (myCollection.add(a) == true)
{
System.out.println(a + " >> added.");
break;
}
else
{
System.out.println(a + "is already in the collection.");
break;
}
}
else
{
System.out.println("Invalid Date!");
break;
}
case "D":
Album d = new Album();
d.MakeAlbum(output);
//removing from same collection object created previously
if (myCollection.remove(d) == true)
{
System.out.println(d.getTitle() + "::" + d.getArtist() + " >> deleted.");
break;
}
else
{
System.out.println(d.getTitle() + "::" + d.getArtist() + " >> is not in the collection.");
break;
}
}
}
Should be all that takes to make your program work, now you're always just adding and subtracting from a single Collection object. Before, you were creating a new collection object per switch, and these objects couldn't be accessed at the end of the while loop.
Do this for the rest of your switch statements! I've only done the first two here. Let me know if it runs!
I'm creating a resizeable Object Array. Below is my add function in which I pass through the object I want to add into my arraylist.
The function works, however if someone could explain this code
temp[theList.length] = toAdd;
I understand that it's adding the parameter argument to the end of the new Arraylist. But what's confusing me is the index that I pass into temp[]. Shouldn't I be including theList.length + 1 rather than just theList.length?
public boolean add(Object toAdd) {
if (toAdd != null) {
Object[] temp = new Object[theList.length + 1];
for (int i = 0; i < theList.length; i++) {
temp[i] = theList[i];
}
temp[theList.length] = toAdd;
theList = temp;
return true;
} else {
System.out.println("Invalid type");
return false;
}
}
Explanation for the add method:
Assume, the size of the theList is 10.
They have created an temp array which takes size as theList + 1, so size of temp is 11.
Now, objects are added to the temp except for the last element tem[10].
For adding the last element, you can use any of the 2 ways:
temp[theList.length] //temp[10]
Or
temp[temp.length-1] //temp[10]
They used the 1st way to add the toAdd object.
You could use a standard method Arrays.copyOf which immediately creates a copy of the input array with the new size (in this case, the length is increased):
import java.util.Arrays;
//...
public boolean add(Object toAdd) {
if (toAdd != null) {
int oldLength = theList.length;
theList = Arrays.copyOf(theList, oldLength + 1);
theList[oldLength] = toAdd;
return true;
} else {
System.out.println("Cannot add null object");
return false;
}
}
I am doing a online course and I have a problem. i do not understand what is wrong with my code. Can you please take a look and give me a hint? I don't get why the last test is not working. When they add the cat in pos 0 to the list, the list should become [cat, ape, dog, zebra], no?
import java.util.ArrayList;
public class ArrayListMethods
{
ArrayList<String> list; //instance variable
/**
* Constructor for objects of class ArrayListMethods
*/
public ArrayListMethods(ArrayList<String> arrayList)
{
// initialise instance variables
list = arrayList;
}
/**
* Determines if the array list is sorted (do not sort)
* When Strings are sorted, they are in alphabetical order
* Use the compareTo method to determine which string comes first
* You can look at the String compareTo method in the Java API
* #return true if the array list is sorted else false.
*/
public boolean isSorted()
{
boolean sorted = true;
// TODO: Determine if the array is sorted.
for (int i = 0; i < list.size() - 1; i++){
if (list.get(i).compareTo(list.get(i + 1)) < 0){
sorted = true;
}
else {
sorted = false;
}
}
return sorted;
}
}
The tester class used to test the code has this:
import java.util.ArrayList;
public class ArrayListMethodsTester
{
public static void main(String[] args)
{
//set up
ArrayList<String> animals = new ArrayList<String>();
ArrayListMethods zoo = new ArrayListMethods(animals);
zoo.list.add("ape");
zoo.list.add("dog");
soo.list.add("zebra");
//test isSorted
System.out.println(zoo.isSorted());
System.out.println("Expected: true");
zoo.list.add("cat");
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
zoo.list.remove("cat");
zoo.list.add(0,"cat");
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
}
}
You isSorted method only returns false if the last two elements are not sorted. You should add a break after setting the sorted variable to false:
public boolean isSorted() {
boolean sorted = true;
// TODO: Determine if the array is sorted.
for (int i = 0; i < list.size() - 1; i++){
if (list.get(i).compareTo(list.get(i + 1)) < 0){
sorted = true;
}
else {
sorted = false;
break; // Add break here
}
}
return sorted;
}
Or more simply:
public boolean isSorted() {
for (int i = 0; i < list.size() - 1; i++){
if (list.get(i).compareTo(list.get(i + 1)) > 0){
return false;
}
}
return true;
}
The problem is inside your isSorted() method, you are setting the result as false in the first iteration (because cat is not sorted). But in the second iteration it sets the result as true because "ape" is sorted compared with "dog"
The solution is to finish the process once a false is founded.
So change this:
for (int i = 0; i < list.size() - 1; i++){
if (list.get(i).compareTo(list.get(i + 1)) < 0){
sorted = true;
}
else {
sorted = false;
}
}
For this:
for (int i = 0; i < list.size() - 1; i++){
if (list.get(i).compareTo(list.get(i + 1)) < 0){
sorted = true;
}
else {
return false;
}
}
And it will work fine and it will also improve the performance, since there is no need to check the whole array. If the first couple of elements are not sorted, then the array is not sorted
This question is more about best practice than about fetching elements from a list.
I have an ArrayList which I am itaration though by using a simple for-loop. In case a certain keyword shows up, I need to compare the next tree elements to a certain pattern.
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
for (int i=0; i<fileContent.size(); i++)
{
if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
{
// get the next three elements of "fileContent" and see if they match a certain pattern
}
}
return true;
}
My first approach would be to use another for-loop within the actual outler loop and then increment i by 3:
for (int j=i+1; j<=i+3; j++)
{
if (!fileContent.get(j).matches(PATTERN))
{
return false;
}
}
i+=3;
As you see, it is not hard to make the method do what I want it to do, but... I am not sure if there might be a way which you'd call more elegant.
This question is more about best practice than about fetching elements
from a list.
Before going into details few remarks..
NORMAL.equals(fileContent.get(i)) instead of fileContent.get(i).equals(NORMAL) will avoid NullPointerException
Before iterating for next three element you should first check whether your List has next three element or not to avoid ArrayIndexOutOfBoundException
Now If it's about checking for only next three elements and only return false if any of the three element does not match the pattern than you can have something like following,
if (fileContent.size() < i + 3
&& (!fileContent.get(i+1).matches(PATTERN)
|| !fileContent.get(i+2).matches(PATTERN)
|| !fileContent.get(i+3).matches(PATTERN))) {
return false;
}
Problem in this approach is it will not check if your list does not have next three elements.
As for your approach by allowing check of next available elements you can just add one condition to check whether your list has next element or not in loop before calling get method on the list.Your approach to iterate over next three element seems fine but following improvement is needed.
for (int j=i+1; j<=i+3; j++){
if (fileContent.size() < j && !fileContent.get(j).matches(PATTERN)){
return false;
} else {
break;
}
}
In my opinion you should make a method, that takes the array and index to start looking from, and return boolean if it match the three or not. It is the elegant way.
You can do it with just one loop by introducing a state :
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
int state = 0;
for (int i=0; i<fileContent.size(); i++)
{
switch (state) {
case 0:
if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
state++;
break;
case 1:
case 2:
case 3:
if (!fileContent.get(i).matches(PATTERN))
return false;
state = (state + 1) % 4;
break;
}
return true;
}
You could repeat three times and use ++i when getting the element:
for (int j = 0; j < 3; j++) {
if (!fileContent.get(++i).matches(PATTERN)) {
return false;
}
}
Or do something like this with stream:
if (fileContent.stream().skip(i).limit(3).anyMatch(s -> !s.matches(PATTERN))) {
return false;
}
i += 3;
But I think the best solution would be completely changing it and using an Iterator:
private static boolean areVectorArgumentsValid(ArrayList<String> fileContent) {
for (Iterator<String> it = fileContent.iterator(); it.hasNext();) {
String s = it.next();
if (!s.equals(NORMAL) && !s.equals(VERTEX)) {
continue;
}
for (int i = 0; i < 3; i++) {
if (!it.hasNext() || !it.next().matches(PATTERN)) {
return false;
}
}
}
return true;
}
I've been working on an algorithm to loop through one ArrayList containing a custom object. I'm now on hour 20 and I've gotten almost nowhere.
ArrayList<TicketItem> all = new ArrayList<>();
// ... 'all' gets filled here ... //
ArrayList<TicketItem> allCopy = new ArrayList<>(all);
for (int i = allCopy.size() - 1; i > 0; i--) {
TicketItem last = allCopy.get(i);
for (int j = 0; j < all.size(); j++) {
TicketItem compare = all.get(j);
if (last.getInt(TicketItem.TICKET_ITEM_ID) != compare.getInt(TicketItem.TICKET_ITEM_ID)) {
if (last.canBeGrouped(compare)) {
last.put(TicketItem.TICKET_ITEM_NUMBER, compare.getInteger(TicketItem.TICKET_ITEM_NUMBER));
allCopy.set(i, last);
break;
}
}
}
}
This works when it wants to and to be honest, it's probably really ugly. I just can't get my head around a better option.
The important method inside TicketItem is this one:
public boolean canBeGrouped(TicketItem other) {
if (other == null)
return false;
if (getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (other.getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (getInteger(TicketItem.MENU_ITEM) == null)
return false;
if (getInteger(TicketItem.MENU_ITEM).equals(other.getInteger(TicketItem.MENU_ITEM))
&& getBigDecimal(TicketItem.TICKET_ITEM_TOTAL).compareTo(
other.getBigDecimal(TicketItem.TICKET_ITEM_TOTAL)) == 0) {
ArrayList<TicketItemModifier> mThis = getModifiers();
ArrayList<TicketItemModifier> mOther = other.getModifiers();
if (mThis == null && mOther == null)
return true;
if (mThis != null && mOther != null) {
if (mThis.size() == mOther.size()) {
for (int i = 0; i < mThis.size(); i++) {
TicketItemModifier m1 = mThis.get(i);
TicketItemModifier m2 = mOther.get(i);
Integer m1MenuModifierId = m1.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
Integer m2MenuModifierId = m2.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
if (!(m1MenuModifierId != null && m2MenuModifierId != null && m1MenuModifierId
.equals(m2MenuModifierId))) {
return false;
}
}
return true;
}
}
}
return false;
}
Again, super ugly especially the for loop in there that works when it wants to. If need be I can modify hashCode and equals methods for both classes TicketItem and TicketItemModifier, however I would like to stay away from those two methods and do something along the lines of Comparable classes because just because they can be grouped does not mean they are equal.
What I want to do basically is go through one ArrayList filled with TicketItem objects and when two can be grouped I need to change the TicketItem object to match it.
I would suggest you create a new property or function like TickeItemCode which should be string concatenation of MENU_ITEM+ "-"+ TICKET_ITEM_TOTAL+ "-" + MENU_MODIFIER_IDs in modifiers list. you can filter the list to remove items where TICKET_ITEM_VOID is true and then sort by new property TickeItemCode and do grouping. This way you can reduce your time from n^2 to nlogn