Is there a way to give size limit to TreeSet in Java Collections as we do for arrays?
for example in arrays we do,
anArray = new int[10];
An array has a fixed length that must be specified when you create it.
A TreeSet automatically grows as you add elements to it. You cannot set its size. You can only read it.
This threat can help you fixed size list in Java
Also, you can implement your own collection in order to add elements if your limit has not been reached
You can always make your own implementation. Here is an example to get you started; you may find that you wish to tweak it accordingly:
public class BoundedTreeSet<E> extends TreeSet<E> {
private final int limit;
public BoundedTreeSet(final int limit) {
super();
this.limit = limit;
}
public BoundedTreeSet(final int limit, final Collection<? extends E> c) {
super(c);
this.limit = limit;
}
public BoundedTreeSet(final int limit, final Comparator<? super E> comparator) {
super(comparator);
this.limit = limit;
}
public BoundedTreeSet(final int limit, final SortedSet<E> s) {
super(s);
this.limit = limit;
}
#Override
public boolean add(final E e) {
if (size() >= limit) {
return false;
}
return super.add(e);
}
#Override
public boolean addAll(Collection<? extends E> c) {
if (size() + c.size() >= limit) {
return false;
}
return super.addAll(c);
}
}
None of TreeSet's constructors specifies an initial size, it grows when elements are added. And there's no way to limit the maximum size of the data structure. Every time you add() a new element, you'd need to manually check if it has exceeded the maximum size allowed. You can specify this behavior by implementing a subclass that extends from TreeSet and overriding add(), addAll(), and the two constructors that receive a Collection as a parameter.
Here is an implementation of BoundedTreeSet in Apache Solr, which keeps the biggest values when trying to insert into a "full" set :
http://lucene.apache.org/solr/4_6_0/solr-core/org/apache/solr/util/BoundedTreeSet.html
Maven artifact available here :
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-core</artifactId>
<version>4.6.0</version>
</dependency>
The closest you can come to an existing collection with capacity limits is a BlockingQueue. When adding items to the queue, you can specify a zero second (or very small) blocking timeout, so that an exception is thrown when the capacity is exceeded. For more details, see BlockingQueue.offer()
Related
I'm using the Deque to implement a monotonic queue. I know that Deque can be created by both ArrayDeque and LinkedList. Here is the Monotonic class I constructed:
public static class MonotonicQueue {
Deque<Integer> monotonicQueue;
public MonotonicQueue() {
monotonicQueue = new ArrayDeque<>();
}
void push(int n) {
while (!monotonicQueue.isEmpty() && monotonicQueue.getLast() < n) {
monotonicQueue.removeLast();
}
monotonicQueue.addLast(n);
}
int max() {
return monotonicQueue.getFirst();
}
void pop(int n) {
if (!monotonicQueue.isEmpty() && n == monotonicQueue.getFirst()) {
monotonicQueue.removeFirst();
}
monotonicQueue.addLast(n);
}
}
However, the issue appears in the void push(int n) method, which means delete all elements which are < n, and then add n into the queue of the tail. I initialized a variable window in a method and then tried to push an element to update this monotonic queue.
MonotonicQueue window = new MonotonicQueue();
window.push(3);
But it even fails to insert the first element. The weird thing is when I use the second way in the constructor, say LinkedList<> instead of ArrayDeque, it works very well, i.e. 3 can be inserted successfully.
public MonotonicQueue() {
monotonicQueue = new LinkedList<>();
}
I am wondering why one way works but the other can't. What happened here? Thank you!
How do you code an Iterator for a Set? Given that the iterator does not have access to the underlying data storage mechanism, and can only use the Set methods, is it possible to do this?
Every implementation I've managed to find creates the Iterator as an anonymous class; however, I am trying to figure out if there is a clever way to iterate over a Set while only accessing the methods provided by Set.
So far, the best I've managed to come up with looks like this:
import java.util.*;
public class SetIterator<E> implements Iterator
{
protected E[] arrayData;
protected Set<E> set;
protected int index;
protected boolean canRemove;
public SetIterator(Set<E> set)
{
this.set = set;
this.arrayData = (E[]) set.toArray();
this.index = -1;
this.canRemove = false;
}
public E next()
{
if(this.hasNext())
{
this.canRemove = true;
return this.arrayData[++this.index];
}
else
{
throw new NoSuchElementException("There is no next element");
}
}
public boolean hasNext()
{
return this.index + 1 < this.arrayData.length;
}
public void remove()
{
if(this.canRemove)
{
this.set.remove(this.arrayData[index--]);
this.arrayData = (E[]) this.set.toArray();
this.canRemove = false;
}
else
{
throw new IllegalStateException("Cannot remove element before calling next");
}
}
}
But that feels quite kludgy.... Is there a better way?
I think your title doesn't leave much space for answers, but if I use the following as your actual question:
How do you build an Iterator for a Set?
(and understand build as in get an instance of)
I think as PM 77-1 pointed out in the comments:
call the iterator() method on it, which it has since at least Java 1.5.
Keep in mind that it depends on the actual implementation of Set, wether the elements will always be iterated over in the same order.
if we look in AbstractCollection we will see that toArray actually calls the iterator() (abstract method) to produce the array which you will use, so your method still depends on the specific iterator, so you are essentially decorating the iterator.
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
return it.hasNext() ? finishToArray(r, it) : r;
}
Still not sure what you are trying to accomplish, the underlying datastructure of the set will have different (and specific) ways to efficently iterate the data, any generic solution would sacrafice performance, using the iterable interface should be generic enough.
I have a file of Integer[]s that is too large to put in memory. I would like to search for all arrays with a last member of x and use them in other code. Is there a way to use Guava's multimap to do this, where x is the key and stored in memory and the Integer[] is the value and that is stored on disk? In this scenario, the keys are not unique, but key-value pairs are unique. Reading of this multimap (assuming that it's possible) will be concurrent. I'm also open to suggestions of other ways to approach this.
Thanks
You could create a class representing an array on disk (based on its index in the file of arrays), let's call it FileBackedIntArray, and put instances of that as the values of a HashMultimap<Integer, FileBackedIntArray>:
public class FileBackedIntArray {
// Index of the array in the file of arrays
private final int index;
private final int lastElement;
public FileBackedIntArray(int index, int lastElement) {
this.index = index;
this.lastElement = lastElement;
}
public int getIndex() {
return index;
}
public int[] readArray() {
// Read the file and deserialize the array at the associated index
return smth;
}
public int getLastElement() {
return lastElement;
}
#Override
public int hashCode() {
return index;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || o.getClass() != getClass()) {
return false;
}
return index == ((FileBackedIntArray) o).index;
}
}
Do you actually need an Integer[] and not an int[], by the way (i.e. you can have null values)? As you've said in the comments, you don't really need an Integer[], so using intss everywhere will avoid boxing/unboxing and will save a lot of space since you appear to have lots of them. Hopefully you don't have a huge number of possible values for the last element (x).
You then create an instance for each array and read the last element to put it the Multimap without keeping the array around. Populating the Multimap needs to be either sequential or protected with a lock if concurrent, but reading can be concurrent without any protection. You could even create an ImmutableMultimap once the HashMultimap has been populated, to guard against any modification, a safe practice in a concurrent environment.
I have an interesting problem I would like some help with. I have implemented a couple of queues for two separate conditions, one based on FIFO and the other natural order of a key (ConcurrentMap). That is you can image both queues have the same data just ordered differently. The question I have (and I am looking for an efficient way of doing this) if I find the key in the ConcurrentMap based on some criteria, what is the best way of finding the "position" of the key in the FIFO map. Essentially I would like to know whether it is the firstkey (which is easy), or say it is the 10th key.
Any help would be greatly appreciated.
There is no API for accessing the order in a FIFO map. The only way you can do it is iterate over keySet(), values() or entrySet() and count.
I believe something like the code below will do the job. I've left the implementation of element --> key as an abstract method. Note the counter being used to assign increasing numbers to elements. Also note that if add(...) is being called by multiple threads, the elements in the FIFO are only loosely ordered. That forces the fancy max(...) and min(...) logic. Its also why the position is approximate. First and last are special cases. First can be indicated clearly. Last is tricky because the current implementation returns a real index.
Since this is an approximate location, I would suggest you consider making the API return a float between 0.0 and 1.0 to indicate relative position in the queue.
If your code needs to support removal using some means other than pop(...), you will need to use approximate size, and change the return to ((id - min) / (max - min)) * size, with all the appropriate int / float casting & rounding.
public abstract class ApproximateLocation<K extends Comparable<K>, T> {
protected abstract K orderingKey(T element);
private final ConcurrentMap<K, Wrapper<T>> _map = new ConcurrentSkipListMap<K, Wrapper<T>>();
private final Deque<Wrapper<T>> _fifo = new LinkedBlockingDeque<Wrapper<T>>();
private final AtomicInteger _counter = new AtomicInteger();
public void add(T element) {
K key = orderingKey(element);
Wrapper<T> wrapper = new Wrapper<T>(_counter.getAndIncrement(), element);
_fifo.add(wrapper);
_map.put(key, wrapper);
}
public T pop() {
Wrapper<T> wrapper = _fifo.pop();
_map.remove(orderingKey(wrapper.value));
return wrapper.value;
}
public int approximateLocation(T element) {
Wrapper<T> wrapper = _map.get(orderingKey(element));
Wrapper<T> first = _fifo.peekFirst();
Wrapper<T> last = _fifo.peekLast();
if (wrapper == null || first == null || last == null) {
// element is not in composite structure; fifo has not been written to yet because of concurrency
return -1;
}
int min = Math.min(wrapper.id, Math.min(first.id, last.id));
int max = Math.max(wrapper.id, Math.max(first.id, last.id));
if (wrapper == first || max == min) {
return 0;
}
if (wrapper == last) {
return max - min;
}
return wrapper.id - min;
}
private static class Wrapper<T> {
final int id;
final T value;
Wrapper(int id, T value) {
this.id = id;
this.value = value;
}
}
}
If you can use a ConcurrentNavigableMap, the size of the headMap gives you exactly what you want.
I'm looking for a data structure that is basically a bounded stack.
If I declare that the stack can hold at most 3 items, and I push another item in,
the oldest item is popped.
You'll be able to implement this using a wrapper over a deque (http://en.wikipedia.org/wiki/Deque), or double-ended queue. Just make sure to call the pollLast method inside the offerFirst method if the stack size is reached.
I'd write my own Deque implementation based on a ring buffer.
You need a queue. A singly linked list that records the first and last items.
A doubly linked one if you would like to change from O(n) to O(1) traversal to update the last item.
You push objects at the front of the queue. And if the length is greater than 3, you pop the back.
Well a LIFO (Last In First Out) structure is known as a Stack which is what you need for the main part of your requirement
A FIFO (First In First Out) structure is known as a Queue which is what you need for the ability to pop the oldest Items off the back.
A combination of these is known as a Deque. Where you have to the ability to push or pop from either end.
I'm not sure if Java has a built-in Deque datastructure, but if it does (or you can find an implementation on google), You can just put some wrapping logic around to ensure that if you push to the front, and the deque.Count > 3, then also pop from the back.
This is in C# as I don't know Java I'm afraid but the idea should translate.
public class BoundedStack<T>
{
private readonly int limit;
private LinkedList<T> list;
public BoundedStack(int limit)
{
this.limit = limit;
list = new LinkedList<T>();
}
public void Push(T item)
{
if (list.Count == limit) list.RemoveFirst();
list.AddLast(item);
}
public T Pop()
{
if (list.Count == 0)
throw new IndexOutOfRangeException("No items on the stack");
var item = list.Last.Value;
list.RemoveLast();
return item;
}
public int Count()
{
return list.Count;
}
}
Apache commons has something close to what you need except it is Fifo: CircularFifoBuffer. I think you will be stuck writing a custom wrapper to make a Lifo like implementation.
Here is my LIFO implementation, inspired by Garry Shutler's answer
public class BoundedStack<T> {
private int limit;
private LinkedList<T> list;
public BoundedStack(int limit) {
this.limit = limit;
list = new LinkedList<>();
}
public void push(T item) {
if (list. size() == limit) {
list.removeLast();
}
list.addFirst(item);
}
public int size() {
return list.size();
}
public List<T> getAll() {
return list;
}
public T peek() {
return list.get(0);
}
}