Is there a way to iterate over Java SparseArray (for Android) ? I used sparsearray to easily get values by index. I could not find one.
Seems I found the solution. I hadn't properly noticed the keyAt(index) function.
So I'll go with something like this:
for(int i = 0; i < sparseArray.size(); i++) {
int key = sparseArray.keyAt(i);
// get the object by the key.
Object obj = sparseArray.get(key);
}
If you don't care about the keys, then valueAt(int) can be used to while iterating through the sparse array to access the values directly.
for(int i = 0, nsize = sparseArray.size(); i < nsize; i++) {
Object obj = sparseArray.valueAt(i);
}
Ooor you just create your own ListIterator:
public final class SparseArrayIterator<E> implements ListIterator<E> {
private final SparseArray<E> array;
private int cursor;
private boolean cursorNowhere;
/**
* #param array
* to iterate over.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterate(SparseArray<E> array) {
return iterateAt(array, -1);
}
/**
* #param array
* to iterate over.
* #param key
* to start the iteration at. {#link android.util.SparseArray#indexOfKey(int)}
* < 0 results in the same call as {#link #iterate(android.util.SparseArray)}.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterateAtKey(SparseArray<E> array, int key) {
return iterateAt(array, array.indexOfKey(key));
}
/**
* #param array
* to iterate over.
* #param location
* to start the iteration at. Value < 0 results in the same call
* as {#link #iterate(android.util.SparseArray)}. Value >
* {#link android.util.SparseArray#size()} set to that size.
* #return A ListIterator on the elements of the SparseArray. The elements
* are iterated in the same order as they occur in the SparseArray.
* {#link #nextIndex()} and {#link #previousIndex()} return a
* SparseArray key, not an index! To get the index, call
* {#link android.util.SparseArray#indexOfKey(int)}.
*/
public static <E> ListIterator<E> iterateAt(SparseArray<E> array, int location) {
return new SparseArrayIterator<E>(array, location);
}
private SparseArrayIterator(SparseArray<E> array, int location) {
this.array = array;
if (location < 0) {
cursor = -1;
cursorNowhere = true;
} else if (location < array.size()) {
cursor = location;
cursorNowhere = false;
} else {
cursor = array.size() - 1;
cursorNowhere = true;
}
}
#Override
public boolean hasNext() {
return cursor < array.size() - 1;
}
#Override
public boolean hasPrevious() {
return cursorNowhere && cursor >= 0 || cursor > 0;
}
#Override
public int nextIndex() {
if (hasNext()) {
return array.keyAt(cursor + 1);
} else {
throw new NoSuchElementException();
}
}
#Override
public int previousIndex() {
if (hasPrevious()) {
if (cursorNowhere) {
return array.keyAt(cursor);
} else {
return array.keyAt(cursor - 1);
}
} else {
throw new NoSuchElementException();
}
}
#Override
public E next() {
if (hasNext()) {
if (cursorNowhere) {
cursorNowhere = false;
}
cursor++;
return array.valueAt(cursor);
} else {
throw new NoSuchElementException();
}
}
#Override
public E previous() {
if (hasPrevious()) {
if (cursorNowhere) {
cursorNowhere = false;
} else {
cursor--;
}
return array.valueAt(cursor);
} else {
throw new NoSuchElementException();
}
}
#Override
public void add(E object) {
throw new UnsupportedOperationException();
}
#Override
public void remove() {
if (!cursorNowhere) {
array.remove(array.keyAt(cursor));
cursorNowhere = true;
cursor--;
} else {
throw new IllegalStateException();
}
}
#Override
public void set(E object) {
if (!cursorNowhere) {
array.setValueAt(cursor, object);
} else {
throw new IllegalStateException();
}
}
}
For whoever is using Kotlin, honestly the by far easiest way to iterate over a SparseArray is: Use the Kotlin extension from Anko or Android KTX! (credit to Yazazzello for pointing out Android KTX)
Simply call forEach { i, item -> }
Simple as Pie. Just make sure you fetch array size before actually performing the loop.
for(int i = 0, arraySize= mySparseArray.size(); i < arraySize; i++) {
Object obj = mySparseArray.get(/* int key = */ mySparseArray.keyAt(i));
}
Hope this helps.
For removing all the elements from SparseArray using the above looping leads to Exception.
To avoid this Follow the below code to remove all the elements from SparseArray using normal loops
private void getValues(){
for(int i=0; i<sparseArray.size(); i++){
int key = sparseArray.keyAt(i);
Log.d("Element at "+key, " is "+sparseArray.get(key));
sparseArray.remove(key);
i=-1;
}
}
Here is simple Iterator<T> and Iterable<T> implementations for SparseArray<T>:
public class SparseArrayIterator<T> implements Iterator<T> {
private final SparseArray<T> array;
private int index;
public SparseArrayIterator(SparseArray<T> array) {
this.array = array;
}
#Override
public boolean hasNext() {
return array.size() > index;
}
#Override
public T next() {
return array.valueAt(index++);
}
#Override
public void remove() {
array.removeAt(index);
}
}
public class SparseArrayIterable<T> implements Iterable<T> {
private final SparseArray<T> sparseArray;
public SparseArrayIterable(SparseArray<T> sparseArray) {
this.sparseArray = sparseArray;
}
#Override
public Iterator<T> iterator() {
return new SparseArrayIterator<>(sparseArray);
}
}
If you want to iterate not only a value but also a key:
public class SparseKeyValue<T> {
private final int key;
private final T value;
public SparseKeyValue(int key, T value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public T getValue() {
return value;
}
}
public class SparseArrayKeyValueIterator<T> implements Iterator<SparseKeyValue<T>> {
private final SparseArray<T> array;
private int index;
public SparseArrayKeyValueIterator(SparseArray<T> array) {
this.array = array;
}
#Override
public boolean hasNext() {
return array.size() > index;
}
#Override
public SparseKeyValue<T> next() {
SparseKeyValue<T> keyValue = new SparseKeyValue<>(array.keyAt(index), array.valueAt(index));
index++;
return keyValue;
}
#Override
public void remove() {
array.removeAt(index);
}
}
public class SparseArrayKeyValueIterable<T> implements Iterable<SparseKeyValue<T>> {
private final SparseArray<T> sparseArray;
public SparseArrayKeyValueIterable(SparseArray<T> sparseArray) {
this.sparseArray = sparseArray;
}
#Override
public Iterator<SparseKeyValue<T>> iterator() {
return new SparseArrayKeyValueIterator<T>(sparseArray);
}
}
It's useful to create utility methods that return Iterable<T> and Iterable<SparseKeyValue<T>>:
public abstract class SparseArrayUtils {
public static <T> Iterable<SparseKeyValue<T>> keyValueIterable(SparseArray<T> sparseArray) {
return new SparseArrayKeyValueIterable<>(sparseArray);
}
public static <T> Iterable<T> iterable(SparseArray<T> sparseArray) {
return new SparseArrayIterable<>(sparseArray);
}
}
Now you can iterate SparseArray<T>:
SparseArray<String> a = ...;
for (String s: SparseArrayUtils.iterable(a)) {
// ...
}
for (SparseKeyValue<String> s: SparseArrayUtils.keyValueIterable(a)) {
// ...
}
If you use Kotlin, you can use extension functions as such, for example:
fun <T> LongSparseArray<T>.valuesIterator(): Iterator<T> {
val nSize = this.size()
return object : Iterator<T> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next(): T = valueAt(i++)
}
}
fun <T> LongSparseArray<T>.keysIterator(): Iterator<Long> {
val nSize = this.size()
return object : Iterator<Long> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next(): Long = keyAt(i++)
}
}
fun <T> LongSparseArray<T>.entriesIterator(): Iterator<Pair<Long, T>> {
val nSize = this.size()
return object : Iterator<Pair<Long, T>> {
var i = 0
override fun hasNext(): Boolean = i < nSize
override fun next() = Pair(keyAt(i), valueAt(i++))
}
}
You can also convert to a list, if you wish. Example:
sparseArray.keysIterator().asSequence().toList()
I think it might even be safe to delete items using remove on the LongSparseArray itself (not on the iterator), as it is in ascending order.
EDIT: Seems there is even an easier way, by using collection-ktx (example here) . It's implemented in a very similar way to what I wrote, actally.
Gradle requires this:
implementation 'androidx.core:core-ktx:#'
implementation 'androidx.collection:collection-ktx:#'
Here's the usage for LongSparseArray :
val sparse= LongSparseArray<String>()
for (key in sparse.keyIterator()) {
}
for (value in sparse.valueIterator()) {
}
sparse.forEach { key, value ->
}
And for those that use Java, you can use LongSparseArrayKt.keyIterator , LongSparseArrayKt.valueIterator and LongSparseArrayKt.forEach , for example. Same for the other cases.
The answer is no because SparseArray doesn't provide it. As pst put it, this thing doesn't provide any interfaces.
You could loop from 0 - size() and skip values that return null, but that is about it.
As I state in my comment, if you need to iterate use a Map instead of a SparseArray. For example, use a TreeMap which iterates in order by the key.
TreeMap<Integer, MyType>
The accepted answer has some holes in it. The beauty of the SparseArray is that it allows gaps in the indeces. So, we could have two maps like so, in a SparseArray...
(0,true)
(250,true)
Notice the size here would be 2. If we iterate over size, we will only get values for the values mapped to index 0 and index 1. So the mapping with a key of 250 is not accessed.
for(int i = 0; i < sparseArray.size(); i++) {
int key = sparseArray.keyAt(i);
// get the object by the key.
Object obj = sparseArray.get(key);
}
The best way to do this is to iterate over the size of your data set, then check those indeces with a get() on the array. Here is an example with an adapter where I am allowing batch delete of items.
for (int index = 0; index < mAdapter.getItemCount(); index++) {
if (toDelete.get(index) == true) {
long idOfItemToDelete = (allItems.get(index).getId());
mDbManager.markItemForDeletion(idOfItemToDelete);
}
}
I think ideally the SparseArray family would have a getKeys() method, but alas it does not.
Related
Searching for info about the iterator, I found only examples that showed how to iterate over a collection, and not returning the Iterator, like I want to do.
I am practicing for the exam, so I'm trying out some programming excercises to prepare myself, and this one is about the iterator pattern.
I want to implement the getKnightPositionIterator, . You can see the code below. This code is not mine, I found this.
package iterator;
import java.util.*;
public class Position {
/** return an iterator that will return all positions
* that a knight may reach from a given starting position.
*/
public static Iterator<Position> getKnightPositionIterator(Position p) {
return null;
}
/** create a position.
* #param r the row
* #param c the column
*/
public Position(int r, int c) {
this.r = r; this.c = c;
}
protected int r;
protected int c;
/** get the row represented by this position.
* #return the row.
*/
public int getRow() { return r; }
/** get the column represented by this position.
* #return the column.
*/
public int getColumn() { return c; }
public boolean equals(Object o) {
if (o.getClass() != Position.class) { return false; }
Position other = (Position) o;
return r==other.r && c==other.c;
}
public int hashCode() {
// works ok for positions up to columns == 479
return 479*r+c;
}
public String toString() {
return "["+r+","+c+"]";
}
}
How ever, I figure that I have to create an Iterator to return, so, so far, this is my attemp.
public static Iterator<Position> getKnightPositionIterator(Position p) {
Iterator<Position> knightPosIter = Position.getKnightPositionIterator(p);
for(Iterator<Position> positions = knightPosIter; positions.hasNext(); ) {
//What should I write here?
}
return knightPosIter;
}
First, make your class implement Iterable interface
public class Position implements Iterable<Position>
and write the public Iterator<Positions> iterator(); method as outlined below instead of providing a static method in your example.
As you actually need to compute a collection of reachable positions in one way or another, you will need a structure to hold it. Any such structure will normally be iterable and, thus, will have an iterator method. So a lazy implementation could look like this:
#Override
public Iterator<Position> iterator()
{
// make sure this returns e.g. Collections.unmodifiableList
Collection<Position> positions = computeReachablePositions();
return positions.iterator();
}
In case you have some other structure to compute and store your positions that is not iterable (not advisable), implement an iterator from scratch as follows (an array of positions assumed):
#Override
public Iterator<Position> iterator()
{
// must be final to be accessible from the iterator below
final Position[] positions = computeReachablePositions();
return new Iterator<Position>() {
int index = 0;
#Override
public boolean hasNext()
{
return index < positions.length;
}
#Override
public Position next()
{
if (hasNext())
{
Position value = positions[index];
index++;
return value;
}
throw new NoSuchElementException("No more positions available");
}
#Override
public void remove()
{
throw new UnsupportedOperationException("Removals are not supported");
}};
}
I want them to do a custom iterator, for a wrapper set.
ListIterator from(E elem)
Extend the implementation and add some façade methods
If you want a custom iterator for a Map, do need to use a LinkedHashMap (which iterates in the same order as entries are added). Just use a HashMap and override the entrySet() method:
public class Map<K, V> extends HashMap<K, V> {
public Set<K, V> entrySet() {
return new HashSet<K, V>(super.entrySet()) {
public Iterator<Map.Entry<K, V>> iterator () {
return // some custom implementation
}
};
}
// similar for keySet() if you wish
}
I've got a solution now that doesn't use extension or reflection (or indeed LinkedHashMap)
What do you think?
package i3.util;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* This class is a like LinkedHashSet (insertion order) but it allows querying
* the relative position of a element and has a ListIterator that can set and
* insert anywhere.
*
* Warning: the iterator can change the order of the set by moving elements when
* setting or adding. Elements that already exist are not ignored, but moved the
* requested place. This changes iteration order
*
*
* The iterators of this class are fail fast and will throw a
* ConcurrentModificationException if their iterator are used with intervening
* main class (or other iterators) mutative calls
*
* #author i30817 <i30817#gmail.com>
*/
public class LinkedSet<E> extends AbstractSet<E> {
//It holds the linked list
private Map<E, Node> m = new HashMap<E, Node>();
//head of that
protected Node head = new Node();
//this is copied to the map value in increments of iteratorAddStep on set.add
//(which only adds to the end, by insertion indexing)
private int monotonicallyIncreasing = 0;
//iterator add step may change when doing rebuilds of the 'space' between elements
//for the before/after functions on LinkedKeyIterator.add
private int iteratorAddStep = 10;
//for fail fast iterators
private int modCount;
/**
* Start iterating from elem (inclusive)
*
*
* #throws NoSuchElementException if E not part of the set
* #param elem a element of the set
* #return a ListIterator - doesn't support nextIndex() or previousIndex()
*/
public ListIterator<E> from(E elem) {
Node e = m.get(elem);
if (e == null) {
throw new NoSuchElementException("the given element isn't part of the set");
}
return new LinkedKeyIterator(e);
}
#Override
public ListIterator<E> iterator() {
return new LinkedKeyIterator();
}
/**
* Returns true if the value target was added before (exclusive) limitElem
* in insertion order.
*
* If target or limit are not present on the set this method returns false
*
* #param limitElem a E that may be a element of the set or not.
* #return if target was added before limit (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsBefore(E target, E limitElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer highN = m.get(limitElem).relativeLocation;
return targetN != null && highN != null && targetN < highN;
}
/**
* Returns true if the value target was added after (exclusive) previousElem
* in insertion order.
*
* If target or previous are not present on the set this method returns
* false
*
* #param previousElem a E that may be a element of the set or not.
* #return if target was added before previous (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsAfter(E target, E previousElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer low = m.get(previousElem).relativeLocation;
return targetN != null && low != null && low < targetN;
}
#Override
public boolean add(E e) {
if (!m.containsKey(e)) {
Node n = new Node(e, monotonicallyIncreasing);
monotonicallyIncreasing += iteratorAddStep;
n.addBefore(head);//insertion order
m.put(e, n);
return true;
}
return false;
}
#Override
public int size() {
return m.size();
}
#Override
public boolean isEmpty() {
return m.isEmpty();
}
#Override
public boolean contains(Object o) {
return m.containsKey(o);
}
#Override
public Object[] toArray() {
Object[] result = new Object[size()];
int i = 0;
for (E e : this) {
result[i++] = e;
}
return result;
}
#Override
#SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size) {
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
}
int i = 0;
Object[] result = a;
for (E e : this) {
result[i++] = e;
}
if (a.length > size) {
//peculiar toArray contract where it doesn't care about the rest
a[size] = null;
}
return a;
}
#Override
public boolean remove(Object o) {
Node n = m.remove(o);
if (n != null) {
n.remove();
return true;
}
return false;
}
#Override
public boolean addAll(Collection<? extends E> c) {
boolean changed = false;
for (E e : c) {
changed |= add(e);
}
return changed;
}
#Override
public boolean containsAll(Collection<?> c) {
boolean all = true;
for (Object e : c) {
all &= m.containsKey(e);
}
return all;
}
#Override
public boolean retainAll(Collection<?> c) {
boolean changed = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
E k = it.next();
if (!c.contains(k)) {
it.remove();
changed = true;
}
}
return changed;
}
#Override
public void clear() {
modCount++;
head.after = head.before = head;
m.clear();
}
#Override
public String toString() {
return m.keySet().toString();
}
//linkedlist node class
protected final class Node {
Node before, after;
int relativeLocation;
//needed for map removal during iteration
E key;
private void remove() {
before.after = after;
after.before = before;
modCount++;
}
private void addBefore(Node existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
modCount++;
}
//head const
public Node() {
after = before = this;
relativeLocation = 0;
}
public Node(E key, int value) {
this.key = key;
this.relativeLocation = value;
}
}
protected class LinkedKeyIterator implements ListIterator<E> {
Node nextEntry;
Node lastReturned;
int expectedModCount = modCount;
public LinkedKeyIterator() {
nextEntry = head.after;
}
public LinkedKeyIterator(Node startAt) {
nextEntry = startAt;
}
public boolean hasPrevious() {
return nextEntry.before != head;
}
public boolean hasNext() {
return nextEntry != head;
}
public E next() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry;
nextEntry = e.after;
return e.key;
}
public E previous() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry.before == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry.before;
nextEntry = e;
return e.key;
}
public void remove() {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
m.remove(lastReturned.key);
nextEntry = lastReturned.after;
lastReturned.remove();
lastReturned = null;
expectedModCount = modCount;
}
#Override
public void set(E e) {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (lastReturned.key.equals(e)) {
return;
}
//remove mapping for key since we are changing it
m.remove(lastReturned.key);
//put in the new one
lastReturned.key = e;
Node previousKeyOwner = m.put(e, lastReturned);
if (previousKeyOwner != null) {
//as it is a list mutation call, guard against stale iterator
if(nextEntry == previousKeyOwner){
nextEntry = nextEntry.after;
}
previousKeyOwner.remove();
}
//from m.remove and m.put, may help with 2 concurrent iterators on this instance
//this method may not change modCount if previousKeyOwner is null
expectedModCount = ++modCount;
}
#Override
public void add(E e) {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
//calculate a good relative location, updating subsequent ones if needed
int candidateLoc = nextEntry.before.relativeLocation + 1;
//opsss, it's full
if (candidateLoc == nextEntry.relativeLocation) {
iteratorAddStep *= 1.6;
for (Node current = nextEntry; current != head; current = current.after) {
current.relativeLocation = current.relativeLocation + iteratorAddStep;
}
}
Node n = m.get(e);
if (n == null) {
n = new Node(e, candidateLoc);
m.put(e, n);
} else {
n.relativeLocation = candidateLoc;
//as it is a list mutation call, guard against stale iterator
if(nextEntry == n){
nextEntry = nextEntry.after;
}
n.remove();
}
n.addBefore(nextEntry);
expectedModCount = modCount;//add before changes modCount
}
#Override
public int nextIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public int previousIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
I have an ArrayList filled with objects with attributes name and time. I would like to remove duplicates based on the name and keep only records with the latest time. So I have overriden equals and hashcode for name in my object and used code like this.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
changedRecentlyList.clear(); //static list
for(ChangedRecentlyTO to : toList) {
if(!changedRecentlyList.contains(to)) {
changedRecentlyList.add(to);
} else {
if(changedRecentlyList.get(changedRecentlyList.lastIndexOf(to)).getTimeChanged().before(to.getTimeChanged())) {
changedRecentlyList.remove(to);
changedRecentlyList.add(to);
}
}
}
return changedRecentlyList;
}
But I am wondering, is there a better solution?I was thinking about using Set but I am not able to figure out how should I put there the time criterion.
You have to me two ways, one which requires understanding how the set work, and one which is more understandable for people who have littler understanding of Java Collections:
If you want to make it simple, you can simply read in the detail the Javadoc of Set, http://docs.oracle.com/javase/6/docs/api/java/util/Set.html#add(E). It clearly states that if an element is already inside, it won't be added again.
You implement your equals and hashcode using only the name
You sort the items by time and then you add them to the Set.
In such a way, the first time you will add the item to Set, you will be adding the elements with the latest times. When you'll add the others, they will be ignored because they are already contained.
If someone else who does not know exactly the contract of java.util.Set behaves, you might want to extend Set to make your intention clearer. However, since a Set is not supposed to be accessed to "get back an element after removal", you will need to back your set with an HashMap:
interface TimeChangeable {
long getTimeChanged();
}
public class TimeChangeableSet<E extends TimeCheangeable> implements Set<E> {
private final HashMap<Integer,E> hashMap = new HashMap<Integer,E>();
#Override
public boolean add(E e) {
E existingValue = hashMap.remove(e.hashCode());
if(existingValue==null){
hashMap.put(e.hashCode(),e);
return true;
}
else{
E toAdd = e.getTimeChanged() > existingValue.getTimeChanged() ? e : existingValue;
boolean newAdded = e.getTimeChanged() > existingValue.getTimeChanged() ? true : false;
hashMap.put(e.hashCode(),e);
return newAdded;
}
}
#Override
public int size() {
return hashMap.size();
}
#Override
public boolean isEmpty() {
return hashMap.isEmpty();
}
#Override
public boolean contains(Object o) {
return hashMap.containsKey(o.hashCode());
}
#Override
public Iterator<E> iterator() {
return hashMap.values().iterator();
}
#Override
public Object[] toArray() {
return hashMap.values().toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return hashMap.values().toArray(a);
}
#Override
public boolean remove(Object o) {
return removeAndGet(o)!=null ? true : false;
}
public E removeAndGet (Object o) {
return hashMap.remove(o.hashCode());
}
#Override
public boolean containsAll(Collection<?> c) {
boolean containsAll = true;
for(Object object:c){
E objectInMap = removeAndGet(object);
if(objectInMap==null || !objectInMap.equals(object))
containsAll=false;
}
return containsAll;
}
#Override
public boolean addAll(Collection<? extends E> c) {
boolean addAll=true;
for(E e:c){
if(!add(e)) addAll=false;
}
return addAll;
}
#Override
public boolean retainAll(Collection<?> c) {
boolean setChanged=false;
for(E e: hashMap.values()){
if(!c.contains(e)){
hashMap.remove(e.hashCode());
setChanged=true;
}
}
return setChanged;
}
#Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("Please do not use type-unsafe methods in 2012");
}
#Override
public void clear() {
hashMap.clear();
}
}
Extend HashMap and override put method to put only if new object is more recent than the existing one.
Or, you can create your own dedicated container which will be backed by a HashMap, just like some implementations of Stack are backed by LinkedList
This is a mock code:
import java.util.HashMap;
import java.util.Map;
public class TimeMap<K, V> {
private Map<K, V> timeMap;
public TimeMap() {
this.timeMap = new HashMap<K, V>();
}
public void put(K key, V value) {
if (isNewer(key, value)) {
this.timeMap.put(key, value);
}
}
}
Why you dont use a Set and later:
new ArrayList(set);
A very quick implementation of what I had in mind.
Assumed the ChangedRecentlyTO object had a name property.
private List<ChangedRecentlyTO> groupRecords(List<ChangedRecentlyTO> toList) {
Map<String, ChangedRecentlyTO> uniqueMap = new HashMap<String, ChangedRecentlyTO>();
for(ChangedRecentlyTO to : toList) {
if (uniqueMap.containsKey(to.getName())) {
if (uniqueMap.get(to.getName()).getTimeChanged().before(to.getTimeChanged())) {
uniqueMap.put(to.getName(), to);
}
} else {
uniqueMap.put(to.getName(), to);
}
}
return (List<ChangedRecentlyTO>) uniqueMap.values();
}
After all of that, it doesn't seem to different to your original implementation with the exception that there is no need override hashcode and equals.
You could let your class implement the Comparable interface and make compare check the timestamps you are interested in. If you then sort it (e.g. put all the elements in a TreeSet) and then get them out one by one, only if they don't already exist. Something like this:
public void removeDuplicates(List<MyObject> list){
SortedSet<MyObject> sortedSet = new TreeSet<MyObject>();
sortedSet.addAll(list);
//Now clear the list, and start adding them again
list.clear();
for(MyObject obj : sortedSet){
if(!list.contains(obj) {
list.add(obj);
}
}
return list;
}
This, however, will only work if two objects with different timestamps are not equal! (in the equals() sense of the word
What I would suggest , Make your class Comparable by implementing Comparable interface.Then in comparetTo() based on name and time compare them if object time is recent return 1 else 0(if equal) or -1 .Once you got this functionality you can extend HashMap class and override the put method like.
o1.compareTo(o2) > 0 then simply overwrite the object with latest one.
Adding logic to #Lopina code like
public class MyHashMap extends HashMap<String, MyClass>{
private Map<String, MyClass> timeMap;
public MyHashMap() {
this.timeMap = new HashMap<String, MyClass>();
}
public MyClass put(String key, MyClass value) {
MyClass obj;
if (isNewer(key, value)) {
System.out.println("count");
obj=this.timeMap.put(key, value);
}else{
obj=value;
}
return obj;
}
private boolean isNewer(String key, MyClass value) {
if(this.timeMap.get(key)==null ||( key.equals(value.getName()))&& (this.timeMap.get(key).compareTo(value))<0)
return true;
else
return false;
}
#Override
public int size() {
return this.timeMap.size();
}
#Override
public MyClass get(Object key) {
return this.timeMap.get(key);
}
}
In MyClass implement comparable interface and override compareTo method like below.
#Override
public int compareTo(MyClass o) {
return this.getTime().compareTo(o.getTime());
}
I wrote a UniqueList class that extends an ArrayList to back its data and utilises a HashSet to efficiently reject duplicates. This gives O(1) Random Access Time and many other speed improvements to manually sweeping the dataset.
https://gist.github.com/hopesenddreams/80730eaafdfe816ddbb1
public class UniqueList<T> extends ArrayList<T> implements Set<T>
{
HashMap<T,Integer> hash; // T -> int
public UniqueList()
{
hash = new HashMap<>();
}
/*
* O(n)
* */
#Override
public void add(int location, T object)
{
super.add(location, object);
for( int i = location ; i < size() ; i++ )
{
hash.put(get(i),i);
}
}
/*
* O(1) amortized.
* */
#Override
public boolean add(T object) {
if( hash.containsKey(object) ) return false;
hash.put(object, size());
super.add(object);
return true;
}
/*
* O(MAX(collection.size(),n)) because of the hash-value-shift afterwards.
* */
#Override
public boolean addAll(int location, Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put(t, size());
super.add(t);
bChanged = true;
}
}
for( int i = location + collection.size() ; i < size() ; i ++ )
{
hash.put( get(i) , i );
}
return bChanged;
}
/*
* O(collection.size())
* */
#Override
public boolean addAll(Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put( t , size() );
super.add(t);
bChanged = true;
}
}
return bChanged;
}
/*
* O(n)
* */
#Override
public void clear() {
hash.clear();
super.clear();
}
/*
* O(1)
* */
#Override
public boolean contains(Object object) {
return hash.containsKey(object);
}
/*
* O(collection.size())
* */
#Override
public boolean containsAll(Collection<?> collection) {
boolean bContainsAll = true;
for( Object c : collection ) bContainsAll &= hash.containsKey(c);
return bContainsAll;
}
/*
* O(1)
* */
#Override
public int indexOf(Object object) {
//noinspection SuspiciousMethodCalls
Integer index = hash.get(object);
return index!=null?index:-1;
}
/*
* O(1)
* */
#Override
public int lastIndexOf(Object object)
{
return hash.get(object);
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public T remove(int location) {
T t = super.remove(location);
hash.remove( t );
for( int i = size() - 1 ; i >= location ; i -- )
{
hash.put( get(i) , i );
}
return t;
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
#Override
public boolean remove(Object object) {
Integer i = hash.get( object );
if( i == null ) return false;
remove( i.intValue() );
return true;
}
/*
* O( MAX( collection.size() , ArrayList.removeAll(collection) ) )
* */
#Override
public boolean removeAll(#NonNull Collection<?> collection) {
for( Object c : collection )
{
hash.remove( c );
}
return super.removeAll( collection );
}
}
My code compiles but doesn't work. I think i didn't typecast right? and can someone explain to me wrapIdx method return index % capacity. i don't really understand how that code wraps the array. when it reaches the end of the array index % capacity will return 1, but doesn't an array start at 0 index?
Here's my code, i'm implementing a Queue12 interface. After i get this to work, will i be able to make a test class to check if it works?
import java.util.NoSuchElementException;
public class QueueImpl12<T> implements Queue12<T>
{
private int _size, _backIdx, _frontIdx;
private static final int _defaultCapacity = 128;
private T[] _ringBuffer;
public QueueImpl12(int capacity)
{
_ringBuffer = (T[]) new Object[capacity];
clear();
}
public QueueImpl12()
{
_ringBuffer = (T[]) new Object[_defaultCapacity];
clear();
}
private int wrapIdx(int index)
{
return index % capacity();
}
public void clear()
{
_backIdx = 0;
_frontIdx = 0;
_size = 0;
}
#Override
public int capacity()
{
// TODO Auto-generated method stub
return _ringBuffer.length;
}
#Override
public int size()
{
// TODO Auto-generated method stub
return _size;
}
#Override
public boolean enqueue(T o)
{
//add o to back of queue
if(_ringBuffer.length == _size)
{
return false;
}
_ringBuffer[_backIdx] = o;
_backIdx = wrapIdx(_backIdx + 1 );
_size++;
return true;
}
#Override
public T dequeue()
{
if(_size == 0) //empty list
{
throw new NoSuchElementException();
}
T tempObj = _ringBuffer[_frontIdx]; //store frontIdx object
_ringBuffer[_frontIdx] = null;
_frontIdx++;
_size--;
return tempObj;
}
#Override
public T peek()
{
return _ringBuffer[_frontIdx];
}
}
So the first thing to note here is that the modulo operator % returns the remainder of a division. Any number modulo itself is 0, therefore when you hit the maximum capacity of the queue it will return 0, which is the index you will start at. If the code is returning 1 when it hits the end, you have an off by one issue.
I have a list of hosts in an array which represnt the servers available to do a particular job. Currently I simply iterate thru the list looking and establish comms with a host to check its not busy. If not I will send a job to it. This approach tends to mean that the first host in the list tends to get hot constanly with the load not balanced properly with the rest of the available hosts.
in pseudocode ..
for (Host h : hosts) {
//checkstatus
if status == job accepted break;
}
I'd like to balance this load properly between the hosts i.e first time host one is used 2nd time the method is used host 2. Just wondering that the most elegant solution to this is ??
Thanks
W
Google collections has a utility method Iterators.cycle(Iterable<T> iterable) that does what you want.
You can create a new kind of Iterable that provides round-robin iteration:
public class RoundRobin<T> implements Iterable<T> {
private List<T> coll;
public RoundRobin(List<T> coll) { this.coll = coll; }
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index = 0;
#Override
public boolean hasNext() {
return true;
}
#Override
public T next() {
T res = coll.get(index);
index = (index + 1) % coll.size();
return res;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
You need to define your hosts as RoundRobin<Host>.
[FIXED based on Mirko's comment]
If the list is mutable and the cost of editing it is negligible compared to I/O with the hosts, you can just rotate it:
List<String> list = Arrays.asList("one", "two", "three");
Collections.rotate(list, -1);
System.out.println(list);
IMHO the standard Java API already provides an easy way to accomplish this, without resorting to external libraries or even the need to implement a custom Iterator. Simply use a Deque where you'd pull the first server, use or discard it, then append it back to the end of the Deque. Here's some sample code:
// Initialize the Deque. This might be at your class constructor.
Deque<Host> dq = new ArrayDeque<Host>();
dq.addAll(Arrays.asList(hosts));
void sendJob(Job myJob) {
boolean jobInProcess = false;
do {
Host host = dq.removeFirst(); // Remove the host from the top
if(!host.isBusy()) {
host.sendJob(myJob);
jobInProcess = true;
}
dq.addLast(host); // Put the host back at the end
}
while(!jobInProcess); // Might add another condition to prevent an infinite loop...
}
This is just a sample where you always ping hosts in round robin order in a loop that only ends when one of them is available and takes the job. You could tinker with it easily to go only around the queue once (use a counter with a max set to the queue's size) or a number of times beofre throwing an exception, or sleeping in between rounds to avoid banging the hosts when all are busy.
My RoundRobin implementation, based upon the implementation of https://stackoverflow.com/a/2041772/1268954
/**
*
* #author Mirko Schulze
*
* #param <T>
*/
public class RoundRobin<T> implements Iterable<T> {
private final List<T> coll;
public RoundRobin(final List<T> coll) {
this.coll = NullCheck.throwExceptionIfNull(coll, "collection is null");
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index;
#Override
public boolean hasNext() {
return true;
}
#Override
public T next() {
this.index = this.index % RoundRobin.this.coll.size();
final T t = RoundRobin.this.coll.get(this.index);
this.index++;
return t;
}
#Override
public void remove() {
throw new IllegalArgumentException("remove not allowd");
}
};
}
}
And the Junit TestCase
/**
*
* #author Mirko Schulze
*
*/
#RunWith(JUnit4.class)
public class RoundRobinTest extends TestCase {
private List<Integer> getCollection() {
final List<Integer> retval = new Vector<Integer>();
retval.add(Integer.valueOf(1));
retval.add(Integer.valueOf(2));
retval.add(Integer.valueOf(3));
retval.add(Integer.valueOf(4));
retval.add(Integer.valueOf(5));
return retval;
}
#Test
public void testIteration() {
final List<Integer> l = this.getCollection();
final Integer frst = l.get(0);
final Integer scnd = l.get(1);
final Integer thrd = l.get(2);
final Integer frth = l.get(3);
final Integer last = l.get(4);
Assert.assertEquals("die Collection hat für diesen Test nicht die passende Größe!", 5, l.size());
final RoundRobin<Integer> rr = new RoundRobin<Integer>(l);
final Iterator<Integer> i = rr.iterator();
for (int collectionIterations = 0; collectionIterations < 4; collectionIterations++) {
final Integer i1 = i.next();
Assert.assertEquals("nicht das erste Element", frst, i1);
final Integer i2 = i.next();
Assert.assertEquals("nicht das zweite Element", scnd, i2);
final Integer i3 = i.next();
Assert.assertEquals("nicht das dritte Element", thrd, i3);
final Integer i4 = i.next();
Assert.assertEquals("nicht das vierte Element", frth, i4);
final Integer i5 = i.next();
Assert.assertEquals("nicht das letzte Element", last, i5);
}
}
}
The implementations provided are buggy and might fail in case of parallelism , the easiest way i did it was to use a circular linked list whose pointer is maintained by an atomic integer.
If you are creating an Iterator, best to create a defensive copy first and have the iterator work on that.
return new MyIterator(ImmutableList.<T>copyOf(list));
public class RoundRobinIterator<T> implements Serializable {
private static final long serialVersionUID = -2472203060894189676L;
//
private List<T> list;
private Iterator<T> it;
private AtomicInteger index = new AtomicInteger(0);
public RoundRobinIterator(List<T> list) throws NullPointerException {
super();
if (list==null) {
throw new NullPointerException("List is null");
}
this.list=Collections.unmodifiableList(list);
}
public RoundRobinIterator(Collection<T> values) {
this(new ArrayList<T>(values));
}
public RoundRobinIterator(Iterator<T> values) {
this(copyIterator(values));
}
public RoundRobinIterator(Enumeration<T> values) {
this(Collections.list(values));
}
private final List<T> getList() {
return list;
}
private final Iterator<T> getIt() {
return it;
}
public final int size() {
return list.size();
}
public final synchronized T getNext(Filter<T> filter) {
int start = index.get();
T t = getNext();
T result = null;
while ((result==null) && (start!=getIndex())) {
if (filter.accept(t)) {
result=t;
} else {
t = getNext();
}
}
return result;
}
public final synchronized T getNext() {
if (getIt()==null) {
if (getList().size()==0) {
index.set(0);
return null;
} else {
it = getList().iterator();
index.set(0);
return it.next();
}
} else if (it.hasNext()) {
index.incrementAndGet();
return it.next();
} else {
if (list.size()==0) {
index.set(0);
return null;
} else {
index.set(0);
it = list.iterator();
return it.next();
}
}
}
public final synchronized int getIndex() {
return index.get();
}
private static <T> List<T> copyIterator(Iterator<T> iter) {
List<T> copy = new ArrayList<T>();
while (iter.hasNext()) {
copy.add(iter.next());
}
return copy;
}
}
Where Filter is
public interface Filter<T> {
public boolean accept(T t);
}