|
|
@@ -1,377 +1,377 @@
|
|
|
-/*
|
|
|
- * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
- * @copyright Ranides Atterwim
|
|
|
- * @license WTFPL
|
|
|
- * @url http://ranides.net/projects/assira
|
|
|
- */
|
|
|
-
|
|
|
-package net.ranides.assira.collection;
|
|
|
-
|
|
|
-import java.util.AbstractCollection;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.Collection;
|
|
|
-import java.util.Iterator;
|
|
|
-import net.ranides.assira.generic.Function;
|
|
|
-
|
|
|
-/**
|
|
|
- * Generyczne operacje na kolekcjach. Jeśli to możliwe, korzystać z innych klas
|
|
|
- * dedykowanych dla konkretnego typu kolekcji, ponieważ poniższe metody opierają
|
|
|
- * się głównie na iteratorach i często mają bardzo kiepską złożoność rzędu O(N)
|
|
|
- * @author ranides
|
|
|
- */
|
|
|
-@SuppressWarnings({"PMD.ShortVar"})
|
|
|
-public final class CollectionUtils {
|
|
|
-
|
|
|
- private CollectionUtils() { }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Pobiera index-ty element z kolekcji, lub zwraca wartość domyślną, jeśli
|
|
|
- * kolekcja ma mniejszy rozmiar niż konieczne.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values
|
|
|
- * @param index
|
|
|
- * @param ddefault
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T get(Collection<T> values, int index, T ddefault) {
|
|
|
- if(null == values) { return ddefault; }
|
|
|
- if(index >= values.size() ) { return ddefault; }
|
|
|
- Iterator<T> iterator = values.iterator();
|
|
|
- // pomijamy (index-1) elementów
|
|
|
- for(int i=1; i<index; i++) {
|
|
|
- iterator.next();
|
|
|
- }
|
|
|
- return iterator.next();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Pobiera index-ty element z kolekcji, lub zwraca null, jeśli
|
|
|
- * kolekcja ma mniejszy rozmiar niż konieczne.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values
|
|
|
- * @param index
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T get(Collection<T> values, int index) {
|
|
|
- return get(values, index, null);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Wyszukuje i zwraca pierwszy obiekt o klasie T, lub null, jeśli takiej wartości brak
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values kolekcja, w której obiekt klasy jest szukany
|
|
|
- * @param clazz szukana klasa
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T first(Collection<?> values, Class<T> clazz) {
|
|
|
- if(null == values) { return null; }
|
|
|
- Iterator<?> i = values.iterator();
|
|
|
- while(i.hasNext()) {
|
|
|
- Object value = i.next();
|
|
|
- if(clazz.isInstance(value)) { return clazz.cast(value); }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Wyszukuje i zwraca pierwszy obiekt w kolekcji, lub null, jeśli kolekcja pusta.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values kolekcja, z której obiekt jest zwracany
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T first(Collection<T> values) {
|
|
|
- if(null == values) { return null; }
|
|
|
- return values.isEmpty() ? null : values.iterator().next();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Jeśli obiekt jest kolekcją lub iteratorem zwraca pierwszy element.
|
|
|
- * Jeśli innym obiektem, zwraca po prostu ten obiekt.
|
|
|
- * Jeśli kolekcja jest pusta - zwraca null.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param values kolekcja, iterator lub zwykły obiekt
|
|
|
- * @return psuedo-pierwszy element
|
|
|
- */
|
|
|
- public static Object first(Object values) {
|
|
|
- if(values instanceof Iterable) {
|
|
|
- Iterator<?> iterator =((Iterable)values).iterator();
|
|
|
- return iterator.hasNext() ? iterator.next() : null;
|
|
|
- }
|
|
|
- if(values instanceof Iterator) {
|
|
|
- Iterator<?> iterator =(Iterator)values;
|
|
|
- return iterator.hasNext() ? iterator.next() : null;
|
|
|
- }
|
|
|
- return values;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Wyszukuje i zwraca ostatni obiekt o klasie T, lub null, jeśli takiej wartości brak.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values kolekcja, w której obiekt klasy jest szukany
|
|
|
- * @param clazz szukana klasa
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T last(Collection<?> values, Class<T> clazz) {
|
|
|
- if(null == values) { return null; }
|
|
|
- Iterator<?> i = values.iterator();
|
|
|
- T result = null;
|
|
|
- while(i.hasNext()) {
|
|
|
- Object value = i.next();
|
|
|
- if(clazz.isInstance(value)) { result = clazz.cast(value); }
|
|
|
- }
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Wyszukuje i zwraca pierwszy obiekt w kolekcji, lub null, jeśli kolekcja pusta
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values kolekcja, z której obiekt jest zwracany
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> T last(Collection<T> values) {
|
|
|
- if(null == values) { return null; }
|
|
|
- Iterator<T> i = values.iterator();
|
|
|
- T result = null;
|
|
|
- while(i.hasNext()) { result = i.next(); }
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Jeśli obiekt jest kolekcją lub iteratorem zwraca pierwszy element.
|
|
|
- * Jeśli innym obiektem, zwraca po prostu ten obiekt.
|
|
|
- * Jeśli kolekcja jest pusta - zwraca null.
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param values kolekcja, iterator lub zwykły obiekt
|
|
|
- * @return psuedo-pierwszy element
|
|
|
- */
|
|
|
- public static Object last(Object values) {
|
|
|
- Object result = null;
|
|
|
- if(values instanceof Iterable) {
|
|
|
- Iterator<?> iterator = ((Iterable)values).iterator();
|
|
|
- while(iterator.hasNext()) { result = iterator.next(); }
|
|
|
- return result;
|
|
|
- }
|
|
|
- if(values instanceof Iterator) {
|
|
|
- Iterator<?> iterator = (Iterator)values;
|
|
|
- while(iterator.hasNext()) { result = iterator.next(); }
|
|
|
- return result;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Zwraca rozmiar kolekcji.
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> int size(Collection<T> values) {
|
|
|
- return null == values ? 0 : values.size();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sprawdza czy kolekcja jest pusta.
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T>
|
|
|
- * @param values
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> boolean isEmpty(Collection<T> values) {
|
|
|
- return 0 == size(values);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sprawdza, czy kolekcje mają ten sam rozmiar.
|
|
|
- * Kolekcje, które są równe {@code null} traktowane są jako puste (rozmiar 0).
|
|
|
- *
|
|
|
- * <div class="message-note">{@code null} safe method</div>
|
|
|
- * @param <T1>
|
|
|
- * @param <T2>
|
|
|
- * @param a
|
|
|
- * @param b
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T1,T2> boolean equalSize(Collection<T1> a, Collection<T2> b) {
|
|
|
- return size(a) == size(b);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sprawdza, czy kolekcje zawierają te same elementy ignorując kolejność.
|
|
|
- * Uwaga: bardzo kosztowna metoda, ponieważ kopiuje a następnie sortuje obie
|
|
|
- * kolekcje.
|
|
|
- * @param <T>
|
|
|
- * @param a
|
|
|
- * @param b
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> boolean equalContent(Collection<T> a, Collection<T> b) {
|
|
|
- if( a.size() != b.size() ){
|
|
|
- return false;
|
|
|
- }
|
|
|
- // najpierw spróbujmy tak sprawdzić - takie porównanie powinno być względnie tanie
|
|
|
- // (złożoność O(N)) w porówaniu do następnej metody
|
|
|
- if( a.equals(b) || b.equals(a) ) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- // dużo kopiowania, na dodatek mamy sortowanie, czyli złożoność
|
|
|
- // na pamięć O(N) oraz operacje O(N*log(N)) + O(N)
|
|
|
- Object[] asort = a.toArray();
|
|
|
- Object[] bsort = b.toArray();
|
|
|
- Arrays.sort(asort);
|
|
|
- Arrays.sort(bsort);
|
|
|
- return Arrays.equals(asort, bsort);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Przycina kolekcję jeśli kolekcja ma rozmiar większy od podanej granicy.
|
|
|
- * @param <T>
|
|
|
- * @param values
|
|
|
- * @param size maksymalny rozmiar kolekcji
|
|
|
- * @return
|
|
|
- * "view" kolekcji podanej jako argument. Modyfikacja obciętej kolekcji
|
|
|
- * ma wpływ na kolekcję źródłową.
|
|
|
- */
|
|
|
- public static <T> Collection<T> clip(Collection<T> values, int size) {
|
|
|
- if(values.size() <= size) { return values; }
|
|
|
- return new ClipCollection<T>(values, size);
|
|
|
- }
|
|
|
-
|
|
|
-/* ************************************************************************** */
|
|
|
-
|
|
|
- private static final class ClipIterator<T> implements Iterator<T> {
|
|
|
-
|
|
|
- private final Iterator<T> iterator;
|
|
|
- private final int size;
|
|
|
- private int index;
|
|
|
-
|
|
|
- public ClipIterator(Collection<T> values, int max) {
|
|
|
- this.iterator = values.iterator();
|
|
|
- this.size = max;
|
|
|
- this.index = 0;
|
|
|
- }
|
|
|
- @Override
|
|
|
- public boolean hasNext() {
|
|
|
- return index < size;
|
|
|
- }
|
|
|
- @Override
|
|
|
- public T next() {
|
|
|
- index++;
|
|
|
- return iterator.next();
|
|
|
- }
|
|
|
- @Override
|
|
|
- public void remove() {
|
|
|
- iterator.remove();
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- private static final class ClipCollection<T> extends AbstractCollection<T> {
|
|
|
-
|
|
|
- private final Collection<T> values;
|
|
|
- private final int size;
|
|
|
-
|
|
|
- public ClipCollection(Collection<T> values, int size) {
|
|
|
- this.values = values;
|
|
|
- this.size = size;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Iterator<T> iterator() {
|
|
|
- return new ClipIterator<T>(values, size);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return size;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Konwertuje podany obiekt iterable na kolekcję o rozmiarze równym {@code size}.
|
|
|
- * Ponieważ na podstawie iteratora nie można wydedukować rozmiaru zbioru,
|
|
|
- * podana wartość {@code size} musi być odpowiednia, tzn nie może być
|
|
|
- * większa niż ilość elementów zwróconych przez iterator.
|
|
|
- *
|
|
|
- * @param <T>
|
|
|
- * @param size
|
|
|
- * @param iterable
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T> Collection<T> asCollection(final int size, final Iterable<T> iterable) {
|
|
|
- return new AbstractCollection<T>() {
|
|
|
- @Override
|
|
|
- public Iterator<T> iterator() { return iterable.iterator(); }
|
|
|
- @Override
|
|
|
- public int size() { return size; }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Zwraca iterator transformujący leniwie elementy za pomocą podanej funkcji odwzorującej.
|
|
|
- * @param <T>
|
|
|
- * @param <S>
|
|
|
- * @param iterator
|
|
|
- * @param function
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T,S> Iterator<T> adapt(final Iterator<S> iterator, final Function<T,S> function) {
|
|
|
- return new Iterator<T>() {
|
|
|
- @Override
|
|
|
- public boolean hasNext() {
|
|
|
- return iterator.hasNext();
|
|
|
- }
|
|
|
- @Override
|
|
|
- public T next() {
|
|
|
- return function.apply(iterator.next());
|
|
|
- }
|
|
|
- @Override
|
|
|
- public void remove() {
|
|
|
- iterator.remove();
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Zwraca kolekcję transformującą leniwie elementy za pomocą podanej funkcji odwzorującej.
|
|
|
- * @param <T>
|
|
|
- * @param <S>
|
|
|
- * @param collection
|
|
|
- * @param function
|
|
|
- * @return
|
|
|
- */
|
|
|
- public static <T,S> Collection<T> adapt(final Collection<S> collection, final Function<T,S> function) {
|
|
|
- return new AbstractCollection<T>() {
|
|
|
- @Override
|
|
|
- public Iterator<T> iterator() {
|
|
|
- return adapt(collection.iterator(), function);
|
|
|
- }
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return collection.size();
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
+/*
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
+ * @license WTFPL
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
+ */
|
|
|
+
|
|
|
+package net.ranides.assira.collection;
|
|
|
+
|
|
|
+import java.util.AbstractCollection;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Iterator;
|
|
|
+import net.ranides.assira.generic.Function;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Generyczne operacje na kolekcjach. Jeśli to możliwe, korzystać z innych klas
|
|
|
+ * dedykowanych dla konkretnego typu kolekcji, ponieważ poniższe metody opierają
|
|
|
+ * się głównie na iteratorach i często mają bardzo kiepską złożoność rzędu O(N)
|
|
|
+ * @author ranides
|
|
|
+ */
|
|
|
+@SuppressWarnings({"PMD.ShortVar"})
|
|
|
+public final class CollectionUtils {
|
|
|
+
|
|
|
+ private CollectionUtils() { }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Pobiera index-ty element z kolekcji, lub zwraca wartość domyślną, jeśli
|
|
|
+ * kolekcja ma mniejszy rozmiar niż konieczne.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values
|
|
|
+ * @param index
|
|
|
+ * @param ddefault
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T get(Collection<T> values, int index, T ddefault) {
|
|
|
+ if(null == values) { return ddefault; }
|
|
|
+ if(index >= values.size() ) { return ddefault; }
|
|
|
+ Iterator<T> iterator = values.iterator();
|
|
|
+ // pomijamy (index-1) elementów
|
|
|
+ for(int i=1; i<index; i++) {
|
|
|
+ iterator.next();
|
|
|
+ }
|
|
|
+ return iterator.next();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Pobiera index-ty element z kolekcji, lub zwraca null, jeśli
|
|
|
+ * kolekcja ma mniejszy rozmiar niż konieczne.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values
|
|
|
+ * @param index
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T get(Collection<T> values, int index) {
|
|
|
+ return get(values, index, null);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Wyszukuje i zwraca pierwszy obiekt o klasie T, lub null, jeśli takiej wartości brak
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values kolekcja, w której obiekt klasy jest szukany
|
|
|
+ * @param clazz szukana klasa
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T first(Collection<?> values, Class<T> clazz) {
|
|
|
+ if(null == values) { return null; }
|
|
|
+ Iterator<?> i = values.iterator();
|
|
|
+ while(i.hasNext()) {
|
|
|
+ Object value = i.next();
|
|
|
+ if(clazz.isInstance(value)) { return clazz.cast(value); }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Wyszukuje i zwraca pierwszy obiekt w kolekcji, lub null, jeśli kolekcja pusta.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values kolekcja, z której obiekt jest zwracany
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T first(Collection<T> values) {
|
|
|
+ if(null == values) { return null; }
|
|
|
+ return values.isEmpty() ? null : values.iterator().next();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Jeśli obiekt jest kolekcją lub iteratorem zwraca pierwszy element.
|
|
|
+ * Jeśli innym obiektem, zwraca po prostu ten obiekt.
|
|
|
+ * Jeśli kolekcja jest pusta - zwraca null.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param values kolekcja, iterator lub zwykły obiekt
|
|
|
+ * @return psuedo-pierwszy element
|
|
|
+ */
|
|
|
+ public static Object first(Object values) {
|
|
|
+ if(values instanceof Iterable) {
|
|
|
+ Iterator<?> iterator =((Iterable)values).iterator();
|
|
|
+ return iterator.hasNext() ? iterator.next() : null;
|
|
|
+ }
|
|
|
+ if(values instanceof Iterator) {
|
|
|
+ Iterator<?> iterator =(Iterator)values;
|
|
|
+ return iterator.hasNext() ? iterator.next() : null;
|
|
|
+ }
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Wyszukuje i zwraca ostatni obiekt o klasie T, lub null, jeśli takiej wartości brak.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values kolekcja, w której obiekt klasy jest szukany
|
|
|
+ * @param clazz szukana klasa
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T last(Collection<?> values, Class<T> clazz) {
|
|
|
+ if(null == values) { return null; }
|
|
|
+ Iterator<?> i = values.iterator();
|
|
|
+ T result = null;
|
|
|
+ while(i.hasNext()) {
|
|
|
+ Object value = i.next();
|
|
|
+ if(clazz.isInstance(value)) { result = clazz.cast(value); }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Wyszukuje i zwraca pierwszy obiekt w kolekcji, lub null, jeśli kolekcja pusta
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values kolekcja, z której obiekt jest zwracany
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> T last(Collection<T> values) {
|
|
|
+ if(null == values) { return null; }
|
|
|
+ Iterator<T> i = values.iterator();
|
|
|
+ T result = null;
|
|
|
+ while(i.hasNext()) { result = i.next(); }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Jeśli obiekt jest kolekcją lub iteratorem zwraca pierwszy element.
|
|
|
+ * Jeśli innym obiektem, zwraca po prostu ten obiekt.
|
|
|
+ * Jeśli kolekcja jest pusta - zwraca null.
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param values kolekcja, iterator lub zwykły obiekt
|
|
|
+ * @return psuedo-pierwszy element
|
|
|
+ */
|
|
|
+ public static Object last(Object values) {
|
|
|
+ Object result = null;
|
|
|
+ if(values instanceof Iterable) {
|
|
|
+ Iterator<?> iterator = ((Iterable)values).iterator();
|
|
|
+ while(iterator.hasNext()) { result = iterator.next(); }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ if(values instanceof Iterator) {
|
|
|
+ Iterator<?> iterator = (Iterator)values;
|
|
|
+ while(iterator.hasNext()) { result = iterator.next(); }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Zwraca rozmiar kolekcji.
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> int size(Collection<T> values) {
|
|
|
+ return null == values ? 0 : values.size();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sprawdza czy kolekcja jest pusta.
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T>
|
|
|
+ * @param values
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> boolean isEmpty(Collection<T> values) {
|
|
|
+ return 0 == size(values);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sprawdza, czy kolekcje mają ten sam rozmiar.
|
|
|
+ * Kolekcje, które są równe {@code null} traktowane są jako puste (rozmiar 0).
|
|
|
+ *
|
|
|
+ * <div class="message-note">{@code null} safe method</div>
|
|
|
+ * @param <T1>
|
|
|
+ * @param <T2>
|
|
|
+ * @param a
|
|
|
+ * @param b
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T1,T2> boolean equalSize(Collection<T1> a, Collection<T2> b) {
|
|
|
+ return size(a) == size(b);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sprawdza, czy kolekcje zawierają te same elementy ignorując kolejność.
|
|
|
+ * Uwaga: bardzo kosztowna metoda, ponieważ kopiuje a następnie sortuje obie
|
|
|
+ * kolekcje.
|
|
|
+ * @param <T>
|
|
|
+ * @param a
|
|
|
+ * @param b
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> boolean equalContent(Collection<T> a, Collection<T> b) {
|
|
|
+ if( a.size() != b.size() ){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // najpierw spróbujmy tak sprawdzić - takie porównanie powinno być względnie tanie
|
|
|
+ // (złożoność O(N)) w porówaniu do następnej metody
|
|
|
+ if( a.equals(b) || b.equals(a) ) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ // dużo kopiowania, na dodatek mamy sortowanie, czyli złożoność
|
|
|
+ // na pamięć O(N) oraz operacje O(N*log(N)) + O(N)
|
|
|
+ Object[] asort = a.toArray();
|
|
|
+ Object[] bsort = b.toArray();
|
|
|
+ Arrays.sort(asort);
|
|
|
+ Arrays.sort(bsort);
|
|
|
+ return Arrays.equals(asort, bsort);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Przycina kolekcję jeśli kolekcja ma rozmiar większy od podanej granicy.
|
|
|
+ * @param <T>
|
|
|
+ * @param values
|
|
|
+ * @param size maksymalny rozmiar kolekcji
|
|
|
+ * @return
|
|
|
+ * "view" kolekcji podanej jako argument. Modyfikacja obciętej kolekcji
|
|
|
+ * ma wpływ na kolekcję źródłową.
|
|
|
+ */
|
|
|
+ public static <T> Collection<T> clip(Collection<T> values, int size) {
|
|
|
+ if(values.size() <= size) { return values; }
|
|
|
+ return new ClipCollection<T>(values, size);
|
|
|
+ }
|
|
|
+
|
|
|
+/* ************************************************************************** */
|
|
|
+
|
|
|
+ private static final class ClipIterator<T> implements Iterator<T> {
|
|
|
+
|
|
|
+ private final Iterator<T> iterator;
|
|
|
+ private final int size;
|
|
|
+ private int index;
|
|
|
+
|
|
|
+ public ClipIterator(Collection<T> values, int max) {
|
|
|
+ this.iterator = values.iterator();
|
|
|
+ this.size = max;
|
|
|
+ this.index = 0;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public boolean hasNext() {
|
|
|
+ return index < size;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public T next() {
|
|
|
+ index++;
|
|
|
+ return iterator.next();
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void remove() {
|
|
|
+ iterator.remove();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final class ClipCollection<T> extends AbstractCollection<T> {
|
|
|
+
|
|
|
+ private final Collection<T> values;
|
|
|
+ private final int size;
|
|
|
+
|
|
|
+ public ClipCollection(Collection<T> values, int size) {
|
|
|
+ this.values = values;
|
|
|
+ this.size = size;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Iterator<T> iterator() {
|
|
|
+ return new ClipIterator<T>(values, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int size() {
|
|
|
+ return size;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Konwertuje podany obiekt iterable na kolekcję o rozmiarze równym {@code size}.
|
|
|
+ * Ponieważ na podstawie iteratora nie można wydedukować rozmiaru zbioru,
|
|
|
+ * podana wartość {@code size} musi być odpowiednia, tzn nie może być
|
|
|
+ * większa niż ilość elementów zwróconych przez iterator.
|
|
|
+ *
|
|
|
+ * @param <T>
|
|
|
+ * @param size
|
|
|
+ * @param iterable
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T> Collection<T> asCollection(final int size, final Iterable<T> iterable) {
|
|
|
+ return new AbstractCollection<T>() {
|
|
|
+ @Override
|
|
|
+ public Iterator<T> iterator() { return iterable.iterator(); }
|
|
|
+ @Override
|
|
|
+ public int size() { return size; }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Zwraca iterator transformujący leniwie elementy za pomocą podanej funkcji odwzorującej.
|
|
|
+ * @param <T>
|
|
|
+ * @param <S>
|
|
|
+ * @param iterator
|
|
|
+ * @param function
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T,S> Iterator<T> adapt(final Iterator<S> iterator, final Function<T,S> function) {
|
|
|
+ return new Iterator<T>() {
|
|
|
+ @Override
|
|
|
+ public boolean hasNext() {
|
|
|
+ return iterator.hasNext();
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public T next() {
|
|
|
+ return function.apply(iterator.next());
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void remove() {
|
|
|
+ iterator.remove();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Zwraca kolekcję transformującą leniwie elementy za pomocą podanej funkcji odwzorującej.
|
|
|
+ * @param <T>
|
|
|
+ * @param <S>
|
|
|
+ * @param collection
|
|
|
+ * @param function
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static <T,S> Collection<T> adapt(final Collection<S> collection, final Function<T,S> function) {
|
|
|
+ return new AbstractCollection<T>() {
|
|
|
+ @Override
|
|
|
+ public Iterator<T> iterator() {
|
|
|
+ return adapt(collection.iterator(), function);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public int size() {
|
|
|
+ return collection.size();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+}
|