Shrinking an ArrayList to a new size - java

Do I really need to implement it myself?
private void shrinkListTo(ArrayList<Result> list, int newSize) {
for (int i = list.size() - 1; i >= newSize; --i)
list.remove(i);
}

Create a sublist with the range of elements you wish to remove and then call clear on the returned list.
list.subList(23, 45).clear()
This approach is mentioned as an idiom in the documentation for both List and ArrayList.
Here's a fully unit tested code example!
// limit yourHappyList to ten items
int k = yourHappyList.size();
if ( k > 10 )
yourHappyList.subList(10, k).clear();
// sic k, not k-1

alternatively you can use subList method:
public static <T> List<T> shrinkTo(List<T> list, int newSize) {
return list.subList(0, newSize - 1);
}

use ArrayList#removeRange() method:
protected void removeRange(int fromIndex,
int toIndex)
Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive. Shifts any succeeding elements to the left (reduces their index). This call shortens the list by (toIndex - fromIndex) elements. (If toIndex==fromIndex, this operation has no effect.)
then use ArrayList#trimToSize() method:
Trims the capacity of this ArrayList instance to be the list's current size. An application can use this operation to minimize the storage of an ArrayList instance.

My solution :
public static void shrinkTo(List list, int newSize) {
int size = list.size();
if (newSize >= size) return;
for (int i = newSize; i < size; i++) {
list.remove(list.size() - 1);
}
}
Just use :
shrinkTo(yourList, 6);

There is another consideration. You might want to shy away from using an ArrayList in your method signature, and instead work to the List interface, as it ties you into theArrayList implementation, making changes down the line difficult if you find that, for example, a LinkedList is more suitable to your needs. Preventing this tight coupling does come at a cost.
An alternative approach could look like this:
private void shrinkListTo(List<Result> list, int newSize) {
list.retainAll(list.subList(0, newSize);
}
Unfortunately, the List.retainAll() method is optional for subclasses to implement, so you would need to catch an UnsupportedOperationException, and then do something else.
private void shrinkListTo(List<Result> list, int newSize) {
try {
list.retainAll(list.subList(0, newSize);
} catch (UnspportedOperationException e) {
//perhaps log that your using your catch block's version.
for (int i = list.size() - 1; i >= newSize; --i)
list.remove(i);
}
}
}
That is not as straight forward as your orginal. If you are not tied to the instance of the List that you are passing in, you could just as easily return a new instance by calling subList(int start, int end), and you wouldnt even need to make a method. This would also be a faster implementation, as (in Java 6), you would be getting an instance of an AbstractList.SubList that contains your list, an offset into it and a size. There would be no need for iterating.
If you are interested in the arguments for coding to Interfaces instead of classes, see this favorite article by Allen Holub

I used:
if (list.size() > newSize) {
list = list.subList(0, newSize);
}

This is the util class I use.
public class ArrayUtil {
public static <T>ArrayList<T> reduceSize(ArrayList<T> models, int size){
int k = models.size();
if ( k > size )
models.subList(size, k).clear();
return models;
}
}
Call it in your main class
ArrayUtil.reduceSize(myArrayList, 10);

Related

Need advise on how to print the remaining capacity of ArrayList

I'm trying to figure out how I can get an output of remaining slots available when 1 object is removed.
ListOfMembers = new ArrayList<>(100); which caps my list at 100.
Whenever I delete 1 from the list, I need to print out the remaining space in the ArrayList.
public boolean DeleteMember() {
Scanner in = new Scanner(System.in);
System.out.println("Enter the membership number: ");
String pno = in. nextLine();
for(int i=0;i<ListOfMembers.size();++i) {
if(ListOfMembers.get(i).getMembershipNumber().equals(pno)) {
ListOfMembers.remove(i);
System.out.println("Space available: " +?????);
return true;
}
}
System.out.println("Numbership number does not exist");
return false;
}
Using System.out.println("Space available: " +ListOfMembers.size()) will provide the count of entries and I'm trying to have the opposite.
You seem to misunderstand how arraylist works.
new ArrayList<>(100) does not cap the list. The 100 is merely a hint.
ArrayList is defined as allowing infinite* growth, and it has no facilities to limit how many items can be in them.
ArrayList works 'under the hood' by having an array that holds your elements. The problem is, java does not allow arrays to grow or shrink. ArrayList solves this problem with two tricks:
By keeping track of the length of the ArrayList internally, the ArrayList impl can use an array that is 'too large'.
If you've filled up your arraylist to have as many items in it as the 'backing array is large', and you add another item, arraylist has a problem - the backing array is out of room. ArrayList will then make a new, larger array, copy over all the elements from the old array, now add the new item (as there is room; this new array is larger), and then get rid of the old array.
The only thing that 100 does in your constructor is serve as a hint: How large should the backing array be made initially. Out of the box (just new ArrayList<>()), you get the default hint of 10.
Try it! run this:
List<String> list = new ArrayList<String>(100);
for (int i = 0; i < 200; i++) list.add("" + i);
System.out.println(list.size());
That code will compile fine, run fine, and print 200. Thus proving that the '100' has absolutely nothing to do with capping the size of this list.
So, how DO you cap a size of an arraylist?
You don't. Arraylist cannot do that. Instead, you wrap, or extend. For serious code bases, I strongly recommend wrapping, but for a simple exercise, extending can make your code a little shorter:
public class LimitedList<T> extends ArrayList<T> {
private final int limit;
public LimitedList(int limit) {
this.limit = limit;
}
#Override public boolean add(T in) {
if (size() >= limit) throw new IllegalStateException("List is full");
super.add(in);
}
#Override public boolean addAll(Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean addAll(int index, Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean add(int idx, T in) {
// left as an exercise for the reader
}
#Override public List<T> subList(int from, int to) {
// this one gets complicated!
// let's just not allow it.
throw new UnsupportedOperationException();
}
public int available() {
return limit - size();
}
}
NB: As you can see, you have to be very careful and override every method that may grow the list; this is why making a new type that doesn't extend ArrayList at all, and instead has 1 field of type ArrayList (and 1 field of int for the limit, of course), can be better: Now you explicitly have to think about every method list has, instead of praying you covered all the ones that add things.
*) well, pragmatically speaking, you can't have more than 2^31-1 elements.
Reading the specification of List, it says that implementations can simply not implement add; or refuse to add elements based on type, or some property of the element; but it doesn't say that a list can refuse to add an element based on the list's current size. Placing a cap on the size thus violates Liskov Substitutability.
You can define a LimitedSizeList implements Collection, but it can't be a true implementation of java.util.List.
You can easily implement LimitedSizeList by extending AbstractCollection:
class LimitedSizeList<E> extends AbstractCollection<E> {
private final List<E> list = new ArrayList<>();
private final int capacity;
LimitedSizeList(int capacity) {
this.capacity = capacity;
}
// Fill in the methods described in the Javadoc:
#Override
public Iterator<E> iterator() { return list.iterator(); }
#Override
public int size() { return list.size(); }
#Override
public boolean add(E element) {
// Collection.add does allow you to throw an IllegalStateException
// https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#add-E-
if (remainingCapacity() <= 0) throw new IllegalStateException("Full");
return list.add(element)
}
// You don't have to, but you might want to consider overriding
// addAll, in order to make trying to add too-large a collection
// failure atomic (that is, it fails to add any rather than some).
// And then provide a method to report the free capacity:
int remainingCapacity() {
return capacity - size();
}
}
This is a far cleaner way to approach the problem than attempting to extend ArrayList (not just because of the contract violation, but also for all the reasons to prefer composition over inheritance).
Of course, if you really want it to be an invalid List (or you can guarantee that it won't need to be treated as a general-purpose List), you can instead extend AbstractList: the methods you need to implement are different, but there are relatively few, and they're quite easy. However, violating contracts is a good way to get surprising bugs in surprising places in your code.
Capacity is an internal metric that is used to dynamically increase the available space used by the ArrayList<>() Usually, it is of no consequence to the user how this is managed since it is an internal issue.
However, being able to set the capacity allows the user to specify a value indicative of the initial contents that the list will hold. The advantage is that it allows the list to fill the backing array without having to continually readjust the capacity resulting in a lot of copying of objects.
Adjust capacity
At any time you can also increase the capacity by using the ensureCapacity() method.
Reduce capacity
And you can also release unused capacity by using trimToSize() method. This may free up memory within the JVM.
But none of the above will prevent you from adding addtional entries to the list. They simply allow one to make optimum choices based on a priori knowledge of the data.
You can use reflection to achieve this task to get the capacity first, then subtract the actual size
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("h");
try {
Field field = list.getClass().getDeclaredField("elementData");
field.setAccessible(true);
int cap = Array.getLength(field.get(list));
System.out.println("The capacity: " + cap);
System.out.println("The size: " + list.size());
System.out.println("The remaining capacity: " + (cap - list.size()));
} catch (Exception e) {
e.printStackTrace();
}
}
, output
The capacity: 10
The size: 6
The remaining capacity: 4

Collections.sort() doesn't work for custom Objects

I'm trying to sort my List but this one doesn't work. Method collections.sort() does nothing.
public boolean schedule(){
List<Task> keys = new ArrayList<Task>(g.tasks.keySet());
for(int i = 0; i<keys.size();i++){
System.out.println(keys.get(i).getSize());
}
Collections.sort(keys);
for(int i = 0; i<keys.size();i++){
System.out.println(keys.get(i).getSize());
}
return true;
}
and this is my compareTo() method in Task class:
public int compareTo(Task t1) {
Integer csize = new Integer(t1.size);
int cmp = csize.compareTo(t1.size);
return cmp;
}
What is wrong in this method?
collections.sort doesn't work for custom objects
Sure it does, but it won't in your case because your compareTo method is broken. You're comparing t1's size to itself, not to the size of this
You've got:
public int compareTo(Task t1) {
Integer csize = new Integer(t1.size); // get t1's size
int cmp = csize.compareTo(t1.size); // ???? compare with t1's size ???
return cmp;
}
You need to change it to something like:
public int compareTo(Task t1) {
return Integer.compare(this.size, t1.size);
}
So now you're comparing the size of the parameter with the size of the current object.
You have an error in compareTo that has been pointed out in the accepted answer. I am supplying an additional answer only to provide a different idiom you might consider for defining natural order of a class:
class Task implements Comparable<Task> {
private static final Comparator<Task> ORDER = Comparator
.comparingInt(Task::getSize)
.reversed()
.thenComparing(Task::getPriority);
public int compareTo(Task other) {
return ORDER.compare(this, other);
}
}
The potential advantage of this delegation idiom is that on casual reading of a traditional compareTo implementation it's easy to miss things such as the order of arguments reversing the comparison. The declaration makes it very explicit. This also means that you have all the features of Comparator available (e.g. deciding if nulls are first or last).
Already answer was posted by #HoverCraft.
In addition to that
//For ASC
public int compareTo(Task t1) {
return (this.size - t1.size);
}
//For DESC
public int compareTo(Task t1) {
return (t1.size - this.size);
}

Android II JAVA Sorting An ArrayList of an object

First of all sorry if my English bad, its not my first language..
I'm working on and android app project, that needed to sort ArrayList of an object..so I made this method to deal with that...
Lets say that I have an object of Restaurant that will contain this data:
private String name;
private float distance ;
And I sort it using the value of the variable distance from lowest to highest:
public void sort(RArrayList<RestaurantData> datas) {
RestaurantData tmp = new RestaurantData();
int swapped;
boolean b = true;
while (b) {
swapped = 0;
for (int i = 0; i < datas.size()-1; i++) {
if (datas.get(i).getDistance() > datas.get(i+1).getDistance()) {
tmp = datas.get(i);
datas.set(i, datas.get(i+1));
datas.set(i+1, tmp);
swapped = 1;
System.err.println("Swapped happening");
}
}
if (swapped == 0) {
System.err.println("Swapped end");
break;
}
}
But when i try the program..the result of an ArrayList is still random, is there any problem with my logic to sort the ArrayList of an object..
Please Help...Thankyou..
Why not use the Collections.sort method?
Here's how you could do it in your project:
public void sort(RArrayList<RestaurantData> datas) {
Collections.sort(datas, new Comparator<RestaurantData>() {
#Override
public int compare(RestaurantData lhs, RestaurantData rhs) {
return lhs.getDistance() - rhs.getDistance();
}
});
}
The above solution is a bit "destructive" in the sense that it changes the order of the elements in the original array - datas. If that's fine for you go ahead and use it. Personally I prefer things less destructive and if you have the memory to spare (meaning your array is small) you could consider this solution which copies the array before sorting. It also assumes your RArrayList is an implementation of ArrayList or backed up by it:
public List<RestaurantData> sort(RArrayList<RestaurantData> datas) {
// Create a list with enough capacity for all elements
List<RestaurantData> newList = new RArrayList<RestaurantData>(datas.size());
Collections.copy(newList, datas);
Collections.sort(newList, new Comparator<RestaurantData>() {
#Override
public int compare(RestaurantData lhs, RestaurantData rhs) {
return lhs.getDistance() - rhs.getDistance();
}
});
return newList;
}
Another thing to consider is also to create a single instance of the Comparator used in the method, since this implementation will create one instance per call. Not sure if it's worth it though, because it will also be destroyed quite soon since the scope is local.
Here's the documentation for the Collections api
One last thing, the comparator simply needs to return a value less than 0 if the elements are in the right order, bigger than 0 if they're in the wrong order or 0 if they're the same. Therefore it seems to be that it's enough to simply subtract the distances of each restaurant. However, if this isn't the case, please implement the comparator suiting your needs.

How do I remove an element from an array in Java? And how do I skip null array elements?

I'm working through a class assignment and I'm not sure how to remove an element from an array. I've read suggestions to use ArrayUtils or convert the array to a linked list. I'm still very new to Java, so I'm not sure if I actually need to do something like this or if I'm overlooking something that's much simpler. I also need to complete a couple of processes that require skipping all null elements in the array. I don't have a great professor and communication attempts are futile, so I'm hoping someone here can help. My code follows. The relevant bits begin at "public void remove". I'm just posting all of the code in this class to give a fuller picture of what's going on:
public class WatchCollection
{
private Watch watches[]; // an array of references to Watch objects
// watches[i] == null if there is no watch in position i
private int num; // size of the array
private void init(int numberOfWatches) {
watches = new Watch[numberOfWatches];
for (int i=0;i<numberOfWatches;++i)
{
watches[i] = null;
}
num = numberOfWatches;
}
public WatchCollection(int numberOfWatches)
{
init(numberOfWatches);
}
public WatchCollection (Watch w1)
{
init(1);
add(w1);
}
// TODO Define WatchCollection (Watch w1, Watch w2) constructor
public WatchCollection (Watch w1, Watch w2)
{
}
// TODO Define WatchCollection (Watch w1, Watch w2, Watch w3) constructor
public WatchCollection (Watch w1, Watch w2, Watch w3)
{
}
public void add ( Watch w )
{
for(int i=0;i<num;++i)
{
if (watches[i]==null)
{
watches[i]=w;
return;
}
}
}
public void remove ( Watch w )
{
// TODO Write a code that removes Watch w if it is in the array
}
public int size()
{
// TODO Write a code that returns actual number of watches, skip all null array elements
}
public Watch at( int index)
{
// TODO Write a code that returns a watch with the specified index (skip all null array elements)
// TODO Throw an exception if the index is < 0 or >= actual number of watches
// For example, if the array contains w1 w2 null w3 w4
// index 0 -> w1
// index 1 -> w2
// index 2 -> w3
// index 3 -> w4
// index 4 -> an exception
}
public String toString()
{
String str="{\n";
int index=0;
for(int i=0;i<num;++i)
{
if (watches[i]!=null)
{
str+=" " +index++ + ": " +watches[i] + "\n";
}
}
str+=" }";
return str;
}
}
ArrayList is a builtin class that offers indexed access to elements, the ability to remove arbitrary elements, and dynamic expansion.
Since this is a class assignment, I'll just provide the algorithm to implement a remove method in your array (assuming this is an algorithm course):
function remove (Element element)
int index <- -1
for i <- 0 to num - 1
if (array[i] is equals to element) then
index <- i
break
end if
end for
if index > -1 then
for i <- index to num - 2
array[i] <- array[i+1]
end for
num <- num - 1
end if
end function
If this is an exercise about Java programming, it would be better to declare an ArrayList and use it since it already implements all these methods for you.
Without giving you the answer, here is how you could improve when you have.
public class WatchCollection {
private Watch watches[]; // an array of references to Watch objects
// watches[i] == null if there is no watch in position i
private int num = 0; // size of the array used.
public WatchCollection(int numberOfWatches) {
watches = new Watch[numberOfWatches];
}
public WatchCollection(Watch w1) {
this(1);
add(w1);
}
public void add(Watch w) {
if (watches.length == num + 1)
watches = Arrays.copyOf(watches, num*2);
watches[num++] = w;
}
You should try to keep your solution as simple as possible.
Here All you want is dealing with a Watch objects, so you don't need to use array.
Using ArrayList
is the best way to do your work.
This class has methods for accessing indexed elements, removing indexed element, dynamic expansion of the array etc.
The link leads to the official documentation for the ArrayList class.
Use Arraylist instead of array. if you already have an array, convert that to A

Swapping Two Objects In An ArrayList

I am trying to swap 2 objects within an ArrayList. To accomplish this, I am creating a new list where the objects are swapped, then overwrite the old list entirely with the, swapped list. However, I am having trouble adding the objects from the old list to the new list.
The program takes input from a text file, reads the data into objects (circles and rectangles, which are extensions of GeometricObject) and then adds those objects to an ArrayList called objectList.
Here is the code:
public static <E extends Comparable<E>> void swapCells
(ArrayList<E> objectList, int left, int right) {
/* The user may enter the two indices, "left,"
* and, "right," in any order which they desire.
* Because of this it will be necessary to determine
* which is larger or "right" index, and which is
* the smaller or "left" index
*/
int temp;
ArrayList<GeometricObject> swappedList = new ArrayList<GeometricObject>();
if (left > right) {
// Exchanges left and right
temp = left;
left = right;
right = temp;
}
for (int i = 0; i < objectList.size(); i++) {
if (i == left) {
swappedList.add(objectList.get(right));
System.out.println( swappedList.get(i).getArea());
} else {
swappedList.add((E) objectList.get(i));
}
}
} // End of swapCells
I get the following syntax error, and do not know what to do about it.
The method add(GeometricObject) in the type ArrayList<GeometricObject> is not applicable for the arguments (E)
The error is specifically at, swappedList.add(objectList.get(right)); and also wappedList.add((E) objectList.get(i));.
I do not believe this is exactly the answer your looking for, but it may help.
If you typecast with GeomtricObject you will get a functioning code, however, this defeats the purpose of using a generic if your just going to force it into a Geometric Object.
You also need to add else if to get the left object swapped to right position
You may also want to print out the swappedList to confirm that the action has been completed.
for (int i = 0; i < objectList.size(); i++)
{
if (i == left) {
swappedList.add((GeometricObject) objectList.get(right));
}else if (i == right)
swappedList.add((GeometricObject) objectList.get(left));
else {
swappedList.add((GeometricObject) objectList.get(i));
}
}
EDIT 2:
The following will aid you in the operation you were looking for in generics.
You will need to make a temp and cast it to E. You will also need to use the following code as well in its correct arguments and/or form / notation.
E temp
List.set(____ , _____)
List.get(____ )
If your still having trouble with this swap function look at one that is not Generic.
EDIT 3:
You most likely have the same problem as I do, and you also need to sort the Generic. You can use the selectionSort Method below to help you on the assignment. You will need to change the method so that it works for an ArrayList instead of a Array. This means you will need to make use of the suggestions in EDIT 2 to modify the code below. You may also need to use the compareTo Method.
private static void selectionSort(int[] list, int low, int high) {
if (low < high) {
int posMax = high;
int theMax = list[high];
for (int i = 0; i < high; i++) {
if (list[i] > theMax) {
theMax = list[i];
posMax = i;
}// if
}// for
list[posMax] = list[high];
list[high] = theMax;
selectionSort(list, low, high - 1);
}// if
}
You are trying to add E objects to a list of GeometricObject. That’s why you get an error. Your list swappedList should be of type ArrayList<E>, or better: List<E>.
On the other hand, you can modify the type of the function to:
public static void swapCells(ArrayList<GeometricObject> objectList, int left, int right)
Oh, and do something with this list you’ve built. Your current code just discards it.
I first want to thank everyone who contributed to answering this question. I consulted with my teacher on office hours sometime last week. My teacher had me draw out a mental picture of what the problem was before writing the code, then a physical picture on paper and pencil of the process to be used. Finally after writing the code, here is the solution:
public static <E extends Comparable<E>> void swapCells
(ArrayList<E> objectList, int left, int right) {
/*
* Create a temporary generic object so that the left and
* right objects can be swapped without losing any data.
*/
E temp = objectList.get(left);
// Place the right object into the left position
objectList.set(left, objectList.get(right));
/*
* Place the temporary (left) object into the right
* position.
*/
objectList.set(right, temp);
} // End of swapCells
There was really no need to even create a second array list, when one can simply use a temporary object E.

Categories