How to leftshift an ArrayList
I'm using an ArrayList to hold a history of objects. Each new object I add using the .add method, like:
if(event.getActio开发者_开发知识库n() == MotionEvent.ACTION_UP)
{
if(currentWord != null)
{
wordHist.add(currentWord);
}
if(wordHist.size() > WORDHIST_MAX_COUNT)
{
wordHist.remove(0);
}
}
However I don't want this to grow indefinitely, but to be limited to a certain value. If it reaches this maximum value, I want the oldest object (index 0) to be removed, and the rest to be left shifted, so previous index 1 is now index 0, etc.
How can this be done?
Thanks
ArrayList is not really a good choice in this case, but it can by done by calling remove(0) method. But if you want to do that efficiently, a linked list is better
(edited to make it clear that LinkedList is not generally better than ArrayList, but only in this case)
If it reaches this maximum value, I want the oldest object (index 0) to be removed
Then do wordHist.remove(0)
. That will remove the element at index 0.
To be precise:
wordHist.add(new Word("hello"));
if (wordHist.size() > MAX_SIZE)
wordHist.remove(0);
As user658991 states however, you should be aware of that this is a linear operation, i.e., takes time proportional to the number of elements in the list.
You could do this in constant time using LinkedList
methods add
and removeFirst
.
Another option would be to wrap an array, or ArrayList in a class called something like CircularArrayList
. In circular list structures you'll override the oldest element when adding a new one.
Edit:
Your code works fine:
import java.util.*;
class Test {
static int WORDHIST_MAX_COUNT = 3;
static List<String> wordHist = new ArrayList<String>();
public static void add(String currentWord) {
// VERBATIM COPY OF YOUR CODE
if (true/*event.getAction() == MotionEvent.ACTION_UP*/)
{
if(currentWord != null)
{
wordHist.add(currentWord);
}
if(wordHist.size() > WORDHIST_MAX_COUNT)
{
wordHist.remove(0);
}
}
}
public static void main(String[] args) {
add("a");
add("b");
add("c");
for (int i = 0; i < wordHist.size(); i++)
System.out.printf("i: %d, word: %s%n", i, wordHist.get(i));
System.out.println();
add("d");
for (int i = 0; i < wordHist.size(); i++)
System.out.printf("i: %d, word: %s%n", i, wordHist.get(i));
}
}
Prints:
i: 0, word: a
i: 1, word: b
i: 2, word: c
i: 0, word: b <-- b is now at index 0.
i: 1, word: c
i: 2, word: d
Use the remove( )
method.
Using remove(0)
will remove the element from the 0th index.
U can use list.remove(index)// here index being '0', this internally shifts rest of the array up. An alternative solution wud be to use a queue or dequeue.
One simple implementation of what Op De Cirkel suggested
import java.util.ArrayList;
import java.util.List;
public class SimpleCircularHistory {
private int sizeLimit, start = 0, end = 0;
boolean empty = false;
private List<String> history;
public SimpleCircularHistory(int sizeLimit) {
this.sizeLimit = sizeLimit;
history = new ArrayList<String>(sizeLimit);
}
public void add(String state){
empty = false;
end = (end + 1) % sizeLimit;
if(history.size() < sizeLimit){
history.add(state);
}else {
history.set(end, state);
start = (end + 1) % sizeLimit;
}
}
public String rollBack(){
if(empty){ // Empty
return null;
}else {
String state = history.get(end);
if(start == end){
empty = true;
}else {
end = (end + sizeLimit - 1) % sizeLimit;
}
return state;
}
}
public void print(){
if(empty){
System.out.println("Empty");
}else {
for(int i = start;; i = (i + 1) % sizeLimit){
System.out.println(history.get(i));
if(i == end) break;
}
System.out.println();
}
}
public static void main(String[] args) {
SimpleCircularHistory h = new SimpleCircularHistory(3);
h.add("a");
h.add("b");
h.add("c");
h.add("d");
h.add("e");
h.add("f");
h.print();
h.add("X");
h.add("Y");
h.rollBack();
h.rollBack();
h.print();
h.add("t");
h.add("v");
h.add("w");
h.print();
h.rollBack();
h.rollBack();
h.rollBack();
h.print();
h.rollBack();
h.print();
}
}
This would print out :
d
e
f
f
t
v
w
Empty
Empty
Yeah, I've noticed this behaviour in adroid's lists too. It's REALLY irritating.
Anyway, there is a way to get around it if I don't mind object creation/destruction and the resulting garbage collection (NEVER do this in a onDraw of a surfaceview or something).
What I do is basically have two tracking int's; one to place the new object, and one to remove it:
int trackInt = 0;
int removeInt = 0;
//and then, in the method/class you use this:
Object newobject = new Object();
//add to list
objectList.add(trackInt, newobject);
trackInt++;
if (bugList.size() > 20) //20 is the max number of object you want, ie the maximum size of the list
{
objectList.remove(removeInt);
trackInt = removeInt;
removeInt++;
if (removeInt > 19) //remember, the list is zero indexed!
{
removeInt = 0;
}
}
Commons-collections has exactly what you're looking for:
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/buffer/CircularFifoBuffer.html
精彩评论