/*
* Concept profile generation tool suite
* Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center,
* Rotterdam, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.erasmusmc.collections;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
public class SortedIntListSet implements Set<Integer>, Serializable {
private static final long serialVersionUID = 7178025949709731944L;
protected IntList entries;
public SortedIntListSet() {
entries = new IntList();
}
public SortedIntListSet(int initialCapacity) {
entries = new IntList(initialCapacity);
}
public SortedIntListSet(IntList setEntries) {
// if you use this constructor: know what you are doing!
// the list is expected to be correcly sorted with only unique entries
this.entries = setEntries;
}
public String toString() {
StringBuffer result = new StringBuffer("[");
Iterator<Integer> iter = iterator();
if (iter.hasNext()) {
result.append(iter.next().toString());
}
while (iter.hasNext()) {
result.append(",");
result.append(iter.next().toString());
}
result.append("]");
return result.toString();
}
public boolean add(Integer key) {
int index = binarySearch(key);
if (index < entries.size()) {
int k = entries.getInt(index);
if (key.intValue() == k) {
return false;
}
else
entries.add(index, key);
}
else
entries.add(index, key);
return true;
}
public boolean guidedContains(int key, int low, int high) {
int index = binarySearch(key, low, high);
if (index < entries.size()) {
if (key == entries.getInt(index))
return true;
}
return false;
}
public int indexOf(int key) {
int index = binarySearch(key, 0, entries.size());
if (index < entries.size()) {
if (key == entries.getInt(index))
return index;
}
return -1;
}
public boolean contains(int key) {
return guidedContains(key, 0, entries.size());
}
protected int binarySearch(int key, int low, int high) {
int middle;
while (low < high) {
middle = (low + high) / 2;
if (key > entries.getInt(middle))
low = middle + 1;
else
high = middle;
}
return low;
}
protected int binarySearch(int key) {
int low = 0, high = entries.size();
return binarySearch(key, low, high);
}
public boolean addAll(Collection<? extends Integer> c) {
Iterator<? extends Integer> iterator = c.iterator();
boolean check = false;
while (iterator.hasNext()) {
if (add(iterator.next())) {
check = true;
}
}
return check;
}
public void clear() {
entries.clear();
}
public boolean contains(Object o) {
if (o instanceof Integer) {
Integer id = (Integer) o;
return contains(id.intValue());
}
return false;
}
public boolean containsAll(Collection<?> c) {
Iterator<?> iterator = c.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Integer) {
Integer id = (Integer) o;
if (!contains(id.intValue())) {
return false;
}
}
else
return false;
}
return true;
}
/**
* This is a special function if you know FOR SURE that you have a properly
* sorted intlist with only unique entries, and you would like to set it as
* the list underlying the set. Note that the old list is lost.
*/
public void setSortedList(IntList list) {
entries = list;
}
/** This returns the precious sorted list: Don't fuck it up! (please)
* You can do all that you want now that it is a copy..... GO YOUR GANG !
* */
public IntList getSortedList() {
return new IntList(entries);
}
public boolean isEmpty() {
if (entries.size() == 0)
return true;
else
return false;
}
public Iterator<Integer> iterator() {
return entries.iterator();
}
public boolean remove(Object o) {
if (o instanceof Integer) {
Integer key = (Integer) o;
int index = binarySearch(key);
if (index < entries.size()) {
if (key == entries.getInt(index)) {
entries.remove(index);
return true;
}
}
}
return false;
}
public boolean removeAll(Collection<?> c) {
Iterator<?> it = c.iterator();
boolean check = false;
while (it.hasNext()) {
if (remove(it.next())) {
check = true;
}
}
return check;
}
public boolean retainAll(Collection<?> c) {
Iterator<Integer> it = iterator();
boolean check = false;
while (it.hasNext()) {
Integer current = it.next();
if (!c.contains(current)) {
check = true;
it.remove();
}
}
return check;
}
public int size() {
return entries.size();
}
public Object[] toArray() {
// TODO Auto-generated method stub
return null;
}
public <T> T[] toArray(T[] a) {
// TODO Auto-generated method stub
return null;
}
public SortedIntListSet getSubstraction (SortedIntListSet set2){
//hurryhurry, not perfectly optimized
IntList resultList = new IntList(size());
SortedIntListSet intersect = getIntersection(set2);
for (int i=0;i<entries.size();i++){
int key = entries.getInt(i);
if (!intersect.contains(key)){
resultList.add(key);
}
}
SortedIntListSet result = new SortedIntListSet(resultList);
return result;
}
public SortedIntListSet getIntersection(SortedIntListSet set2) {
SortedIntListSet shorter = set2;
SortedIntListSet longer = this;
if (shorter.size() > longer.size()) {
shorter = longer;
longer = set2;
}
IntList result = new IntList(shorter.size());
IntList top = new IntList(shorter.size() / 2);
int longerlowestIndex = 0;
int longerhighestIndex = longer.size() - 1;
int longerlowest = longer.getKeyForIndex(longerlowestIndex);
int longerhighest = longer.getKeyForIndex(longerhighestIndex);
int shorterlowestIndex = 0;
int shorterhighestIndex = shorter.size() - 1;
while (shorterlowestIndex <= shorterhighestIndex) {
int key = shorter.getKeyForIndex(shorterlowestIndex);
if (key >= longerlowest) {
int index = longer.guidedGetIndexForKey(key, longerlowestIndex, longerhighestIndex + 1);
if (index < longer.size()) {
longerlowestIndex = index;
if (longer.getKeyForIndex(index) == key) {
result.add(key);
}
longerlowest = longer.getKeyForIndex(longerlowestIndex);
}
}
shorterlowestIndex++;
if (shorterlowestIndex < shorterhighestIndex) {
key = shorter.getKeyForIndex(shorterhighestIndex);
if (key <= longerhighest) {
int index = longer.guidedGetIndexForKey(key, longerlowestIndex, longerhighestIndex + 1);
if (index < longer.size()) {
longerhighestIndex = index;
if (longer.getKeyForIndex(index) == key) {
top.add(key);
}
longerhighest = longer.getKeyForIndex(longerhighestIndex);
}
}
shorterhighestIndex--;
}
}
for (int i = top.size() - 1; i >= 0; i--)
result.add(top.getInt(i));
result.trimToSize();
return new SortedIntListSet(result);
}
private int guidedGetIndexForKey(int key, int low, int high) {
return binarySearch(key, low, high);
}
public int getKeyForIndex(int index) {
return entries.getInt(index);
}
public SortedIntListSet overlap(SortedIntListSet other){
IntList result = new IntList();
int i1 = 0;
int i2 = 0;
while (i1 < entries.size() && i2 < other.entries.size()){
int val1 = entries.getInt(i1);
int val2 = other.entries.getInt(i2);
if (val1 == val2) {
result.add(entries.getInt(i1));
i1++;
i2++;
} else if (val1 > val2){
i2++;
} else
i1++;
}
return new SortedIntListSet(result);
}
public int overlapCount(SortedIntListSet other){
int result = 0;
int i1 = 0;
int i2 = 0;
while (i1 < entries.size() && i2 < other.entries.size()){
int val1 = entries.getInt(i1);
int val2 = other.entries.getInt(i2);
if (val1 == val2) {
result++;
i1++;
i2++;
} else if (val1 > val2){
i2++;
} else
i1++;
}
return result;
}
public IntList getEntries(){
return entries;
}
}