commit f7d477442be8ec80e92ecf7e12d576c604c42c1e Author: Klemek Date: Wed Feb 21 18:55:58 2018 +0100 Initial commit v1.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..924c569 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/bin/ +/.classpath +/.project +/.settings/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e2a0a3a --- /dev/null +++ b/README.md @@ -0,0 +1,195 @@ +# BetterLists (by Klemek) + +An extension of the java.util.List interface which include some of the C# LINQ useful functions. + +List classes are extended as well. (ArrayList -> BetterArrayList) + +Current version v1.0 + +Before BetterLists : +```Java +ArrayList contacts = someFunction(); + +ArrayList contactsEmails = new ArrayList<>(); +for(int i = 5; i < contacts.size(); i++){ + if(c.getEmail() != null){ + contactsEmails.add(c.getEmail()); + } +} +``` +With BetterLists : +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList contactsEmails = contacts.skip(5) + .where(c -> c.getEmail() != null) + .select(c -> c.getEmail()); +``` + +NOTE : Please note that, unlike C# LINQ, these functions are not optimized at low levels and will have the same impact as standard loops in your program. + +## Download + +* [betterlists-1.0.jar](../../raw/master/download/betterlists-1.0.jar) +* [betterlists-1.0-sources.jar](../../raw/master/download/betterlists-1.0-sources.jar) + +## All code examples +### List + +| Name | Description | +| :- | :- | +| [all](#all) | Determines whether all elements of the sequence satisfy a condition. | +| [any](#any) | Determines whether any element of the sequence satisfies a condition. | +| [count](#count) | Returns a number that represents how many elements in the specified sequence satisfy a condition. | +| [exclusion](#exclusion) | Produces the set exclusion of two sequences. | +| [first / firstOrDefault](#first-firstordefault) | Returns the first element in the sequence that satisfies a specified condition. (Returns an error if no elements match the condition unless you use the firstOrDefault function) | +| [last / lastOrDefault](#last-lastordefault) | Returns the last element in the sequence that satisfies a specified condition. (Returns an error if no elements match the condition unless you use the lastOrDefault function) | +| [max](#max) | Invokes a transform function on each element of the sequence and returns the maximum nullable Double value. | +| [mean](#mean) | Computes the mean of the sequence of Double values that are obtained by invoking a transform function on each element of the input sequence. | +| [min](#min) | Invokes a transform function on each element of the sequence and returns the minimum nullable Double value. | +| [orderBy / orderByDescending](#orderby-orderbydescending) | Sorts the elements of a sequence in ascending order by using a specified comparer. (You can user orderByDescending to change the order) | +| [reverse](#reverse) | Inverts the order of the elements in the sequence. | +| [select](#select) | Projects each element of a sequence into a new form. | +| [skip / skipWhile](#skip-skipwhile) | Bypasses elements in the sequence as long as a specified condition is true and then returns the remaining elements. | +| [sum](#sum) | Computes the sum of the sequence of Double values that are obtained by invoking a transform function on each element of the input sequence. | +| [take / takeWhile](#take-takewhile) | Returns a specified number of contiguous elements from the start of the sequence. | +| [union](#union) | Produces the set union of two sequences. | +| [where](#where) | Filters a sequence of values based on a predicate. | + +### all +Determines whether all elements of the sequence satisfy a condition. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +boolean allAdults = contacts.all(c -> c.getAge() >= 21); +``` + +### any +Determines whether any element of the sequence satisfies a condition. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +boolean someUnderage = contacts.any(c -> c.getAge() < 21); +``` + +### count +Returns a number that represents how many elements in the specified sequence satisfy a condition. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +int adultsCount = contacts.count(c -> c.getAge() >= 21); +``` + +### exclusion +Produces the set exclusion of two sequences. +```Java +BetterArrayList frenchContacts = BetterArrayList.fromList(someFunction()); +ArrayList validContacts = someOtherFunction(); + +BetterList invalidFrenchContacts = frenchContacts.exclusion(validContacts); +``` + +### first / firstOrDefault +Returns the first element in the sequence that satisfies a specified condition. (Returns an error if no elements match the condition unless you use the `firstOrDefault` function) +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +Contact firstManager = contacts.first(c -> c.isManager()); +``` + +### last / lastOrDefault +Returns the last element in the sequence that satisfies a specified condition. (Returns an error if no elements match the condition unless you use the `lastOrDefault` function) +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +Contact lastRegular = contacts.last(c -> !c.isManager()); +``` + +### max +Invokes a transform function on each element of the sequence and returns the maximum nullable Double value. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +int maxAge = (int)contacts.max(c -> (double)c.getAge()); +``` + +### mean +Computes the mean of the sequence of Double values that are obtained by invoking a transform function on each element of the input sequence. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +int meanAge = (int)contacts.mean(c -> (double)c.getAge()); +``` + +### min +Invokes a transform function on each element of the sequence and returns the minimum nullable Double value. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +int minAge = (int)contacts.min(c -> (double)c.getAge()); +``` + +### orderBy / orderByDescending +Sorts the elements of a sequence in ascending order by using a specified comparer. (You can user `orderByDescending` to change the order) +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList orderedContacts = contacts.orderBy(c -> c.getName); +``` + +### reverse +Inverts the order of the elements in the sequence. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList reversedContacts = contacts.reverse(); +``` + +### select +Projects each element of a sequence into a new form. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList contactsMails = contacts.select(c -> c.getEmail()); +``` + +### skip / skipWhile +Bypasses elements in the sequence as long as a specified condition is true and then returns the remaining elements. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList contacts2 = contacts.skipWhile(c -> c.getEmail().startsWith("society")); +``` + +### sum +Computes the sum of the sequence of Double values that are obtained by invoking a transform function on each element of the input sequence. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +double salary = contacts.skip(c -> c.getSalary()); +``` + +### take / takeWhile +Returns a specified number of contiguous elements from the start of the sequence. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList contacts2 = contacts.takeWhile(c -> c.getEmail().startsWith("society")); +``` + +### union +Produces the set union of two sequences. +```Java +BetterArrayList frenchContacts = BetterArrayList.fromList(someFunction()); +ArrayList validContacts = someOtherFunction(); + +BetterList validFrenchContacts = frenchContacts.union(validContacts); +``` + +### where +Filters a sequence of values based on a predicate. +```Java +BetterArrayList contacts = BetterArrayList.fromList(someFunction()); + +BetterList validContacts = contacts.where(c -> c.getEmail() != null); +``` \ No newline at end of file diff --git a/download/betterlists-1.0-sources.jar b/download/betterlists-1.0-sources.jar new file mode 100644 index 0000000..8c8ede1 Binary files /dev/null and b/download/betterlists-1.0-sources.jar differ diff --git a/download/betterlists-1.0.jar b/download/betterlists-1.0.jar new file mode 100644 index 0000000..3e5c29f Binary files /dev/null and b/download/betterlists-1.0.jar differ diff --git a/src/fr/klemek/betterlists/BetterArrayList.java b/src/fr/klemek/betterlists/BetterArrayList.java new file mode 100644 index 0000000..9e33fbe --- /dev/null +++ b/src/fr/klemek/betterlists/BetterArrayList.java @@ -0,0 +1,83 @@ +package fr.klemek.betterlists; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * An extension of the java.util.ArrayList class which include some of the C# + * LINQ useful functions. + * + * @author Klemek + * + * @see java.util.ArrayList + */ +public class BetterArrayList extends ArrayList implements BetterList { + + private static final long serialVersionUID = 4772544470059394618L; + + /** + * Constructs a list containing the elements of the specified collection, in the + * order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this list + */ + public static BetterArrayList fromList(Collection c) { + return new BetterArrayList(c); + } + + /** + * Constructs an empty list with an initial capacity of ten. + */ + public BetterArrayList() { + super(); + } + + /** + * Constructs a list containing the elements of the specified collection, in the + * order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this list + */ + public BetterArrayList(Collection c) { + super(c); + } + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity + * - the initial capacity of the list + */ + public BetterArrayList(int initialCapacity) { + super(initialCapacity); + } + + /** + * Returns a view of the portion of this list between the specified fromIndex, + * inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the + * returned list is empty.) The returned list is backed by this list, so + * non-structural changes in the returned list are reflected in this list, and + * vice-versa. The returned list supports all of the optional list operations + * supported by this list. This method eliminates the need for explicit range + * operations (of the sort that commonly exist for arrays). Any operation that + * expects a list can be used as a range operation by passing a subList view + * instead of a whole list. (see List.subList) + * + * @param fromIndex + * - low endpoint (inclusive) of the subList + * @param toIndex + * - high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException + * for an illegal endpoint index value (fromIndex < 0 || toIndex > + * size || fromIndex > toIndex) + * @see java.util.List + */ + @Override + public BetterArrayList subList(int fromIndex, int toIndex) { + return (BetterArrayList) ((List) this).subList(fromIndex, toIndex); + } +} diff --git a/src/fr/klemek/betterlists/BetterLinkedList.java b/src/fr/klemek/betterlists/BetterLinkedList.java new file mode 100644 index 0000000..33fa469 --- /dev/null +++ b/src/fr/klemek/betterlists/BetterLinkedList.java @@ -0,0 +1,74 @@ +package fr.klemek.betterlists; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +/** + * An extension of the java.util.LinkedList class which include some of the C# + * LINQ useful functions. + * + * @author Klemek + * + * @see java.util.LinkedList + */ +public class BetterLinkedList extends LinkedList implements BetterList { + + private static final long serialVersionUID = 4837198308074701770L; + + /** + * Constructs a list containing the elements of the specified collection, in the + * order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this list + */ + public static BetterLinkedList fromList(Collection c) { + return new BetterLinkedList(c); + } + + /** + * Constructs an empty list. + */ + public BetterLinkedList() { + super(); + } + + /** + * Constructs a list containing the elements of the specified collection, in the + * order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this list + */ + public BetterLinkedList(Collection c) { + super(c); + } + + /** + * Returns a view of the portion of this list between the specified fromIndex, + * inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the + * returned list is empty.) The returned list is backed by this list, so + * non-structural changes in the returned list are reflected in this list, and + * vice-versa. The returned list supports all of the optional list operations + * supported by this list. This method eliminates the need for explicit range + * operations (of the sort that commonly exist for arrays). Any operation that + * expects a list can be used as a range operation by passing a subList view + * instead of a whole list. (see List.subList) + * + * @param fromIndex + * - low endpoint (inclusive) of the subList + * @param toIndex + * - high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException + * for an illegal endpoint index value (fromIndex < 0 || toIndex > + * size || fromIndex > toIndex) + * @see java.util.List + */ + @Override + public BetterLinkedList subList(int fromIndex, int toIndex) { + return (BetterLinkedList) ((List) this).subList(fromIndex, toIndex); + } + +} diff --git a/src/fr/klemek/betterlists/BetterList.java b/src/fr/klemek/betterlists/BetterList.java new file mode 100644 index 0000000..b520011 --- /dev/null +++ b/src/fr/klemek/betterlists/BetterList.java @@ -0,0 +1,471 @@ +package fr.klemek.betterlists; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.function.Function; + +/** + * An extension of the java.util.List interface which include some of the C# + * LINQ useful functions. + * + * @author Klemek + * + * @see java.util.List + */ +public interface BetterList extends List { + + /** + * Determines whether all elements of the sequence satisfy a condition. + * + * @param predicate + * - A function to test each element for a condition. + * @return true if every element of the source sequence passes the test in the + * specified predicate, or if the sequence is empty; otherwise, false. + */ + public default boolean all(Function predicate) { + for (T element : this) + if (!predicate.apply(element)) + return false; + return true; + } + + /** + * Determines whether any element of the sequence satisfies a condition. + * + * @param predicate + * - A function to test each element for a condition. + * @return true if any elements in the source sequence pass the test in the + * specified predicate; otherwise, false. + */ + public default boolean any(Function predicate) { + for (T element : this) + if (predicate.apply(element)) + return true; + return false; + } + + /** + * Returns the number of elements in the sequence. + * + * @return The number of elements in the input sequence. + */ + public default int count() { + return count(e -> true); + } + + /** + * Returns a number that represents how many elements in the specified sequence + * satisfy a condition. + * + * @param predicate + * - A function to test each element for a condition. + * @return A number that represents how many elements in the sequence satisfy + * the condition in the predicate function. + */ + public default int count(Function predicate) { + int out = 0; + for (T element : this) + if (predicate.apply(element)) + out++; + return out; + } + + /** + * Produces the set exclusion of two sequences. + * + * @param other + * - Another List whose distinct elements form the second set for the + * exclusion. + * @return A List that contains the elements from the first sequence not present + * in the other. + */ + public default BetterList exclusion(List other) { + BetterList out = new BetterArrayList(); + for (T element : this) + if (!other.contains(element)) + out.add(element); + return out; + } + + /** + * Returns the first element in the sequence. + * + * @throws NoSuchElementException + * If the sequence is empty. + * @return The first element in the sequence. + */ + public default T first() { + return first(e -> true); + } + + /** + * Returns the first element in the sequence that satisfies a specified + * condition. + * + * @param predicate + * - A function to test each element for a condition. + * @throws NoSuchElementException + * No element satisfies the condition in predicate or the sequence + * is empty. + * @return The first element in the sequence that passes the test in the + * specified predicate function. + */ + public default T first(Function predicate) { + for (T element : this) + if (predicate.apply(element)) + return element; + throw new NoSuchElementException(); + } + + /** + * Returns the first element of the sequence that satisfies a condition or the + * default value if no such element is found. + * + * @param predicate + * - A function to test each element for a condition. + * @param defaultValue + * - A default value to be returned if no element passes the test + * @return defaultValue if the sequence is empty or if no element passes the + * test specified by predicate; otherwise, the first element in the + * sequence that passes the test specified by predicate. + */ + public default T firstOrDefault(Function predicate, T defaultValue) { + for (T element : this) + if (predicate.apply(element)) + return element; + return defaultValue; + } + + /** + * Returns the first element of the sequence or a default value if the sequence + * is empty. + * + * @param defaultValue + * - A default value to be returned if the sequence is empty + * @return defaultValue if the sequence is empty otherwise, the first element in + * the sequence. + */ + public default T firstOrDefault(T defaultValue) { + return firstOrDefault(e -> true, defaultValue); + } + + /** + * Returns the last element of the sequence. + * + * @throws NoSuchElementException + * If the sequence is empty. + * @return the last element of the sequence. + */ + public default T last() { + return last(e -> true); + } + + /** + * Returns the last element of the sequence that satisfies a specified + * condition. + * + * @param predicate + * - A function to test each element for a condition. + * @throws NoSuchElementException + * No element satisfies the condition in predicate or the sequence + * is empty. + * @return the last element of the sequence that satisfies a specified + * condition. + */ + public default T last(Function predicate) { + T value = null; + for (T element : this) + if (predicate.apply(element)) + value = element; + if (value == null) + throw new NoSuchElementException(); + return value; + } + + /** + * Returns the last element of the sequence that satisfies a condition or the + * default value if no such element is found. + * + * @param predicate + * - A function to test each element for a condition. + * @param defaultValue + * - A default value to be returned if no element passes the test + * @return defaultValue if the sequence is empty or if no element passes the + * test specified by predicate; otherwise, the last element in the + * sequence that passes the test specified by predicate. + */ + public default T lastOrDefault(Function predicate, T defaultValue) { + T value = null; + for (T element : this) + if (predicate.apply(element)) + value = element; + return value == null ? defaultValue : value; + } + + /** + * Returns the last element of the sequence or a default value if the sequence + * is empty. + * + * @param defaultValue + * - A default value to be returned if the sequence is empty + * @return defaultValue if the sequence is empty otherwise, the last element in + * the sequence. + */ + public default T lastOrDefault(T defaultValue) { + return lastOrDefault(e -> true, defaultValue); + } + + /** + * Invokes a transform function on each element of the sequence and returns the + * maximum nullable Double value. + * + * @param selector + * - A transform function to apply to each element. + * @return The value of type Double that corresponds to the maximum value in the + * sequence or null if the sequence is empty. + */ + public default Double max(Function selector) { + Double max = null; + for (T element : this) + if (max == null || selector.apply(element) > max) + max = selector.apply(element); + return max; + } + + /** + * Computes the mean of the sequence of Double values that are obtained by + * invoking a transform function on each element of the input sequence. + * + * @param selector + * - A transform function to apply to each element. + * @return The mean of the projected values. Null if the sequence contains no + * elements. + */ + public default Double mean(Function selector) { + int count = this.count(); + if (count == 0) + return null; + return this.sum(selector) / this.count(); + } + + /** + * Invokes a transform function on each element of the sequence and returns the + * minimum nullable Double value. + * + * @param selector + * - A transform function to apply to each element. + * @return The value of type Double that corresponds to the minimum value in the + * sequence or null if the sequence is empty. + */ + public default Double min(Function selector) { + Double min = null; + for (T element : this) + if (min == null || selector.apply(element) < min) + min = selector.apply(element); + return min; + } + + /** + * Sorts the elements of a sequence in ascending order by using a specified comparer. + * @param selector + * - A transform function to apply to each element. + * @return a List whose elements are sorted according to a key. + */ + public default > BetterList orderBy(Function selector){ + BetterList out = new BetterArrayList(); + out.addAll(this); + Collections.sort(out, new Comparator() { + + @Override + public int compare(T o1, T o2) { + return selector.apply(o1).compareTo(selector.apply(o2)); + } + + }); + return out; + } + + /** + * Sorts the elements of a sequence in descending order by using a specified comparer. + * @param selector + * - A transform function to apply to each element. + * @return a List whose elements are sorted according to a key. + */ + public default > BetterList orderByDescending(Function selector){ + BetterList out = new BetterArrayList(); + out.addAll(this); + Collections.sort(out, new Comparator() { + + @Override + public int compare(T o1, T o2) { + return selector.apply(o2).compareTo(selector.apply(o1)); + } + + }); + return out; + } + + /** + * Inverts the order of the elements in the sequence. + * + * @return A sequence whose elements correspond to those of the sequence in + * reverse order. + */ + public default BetterList reverse() { + BetterList out = new BetterArrayList(); + for (T element : this) + out.add(0, element); + return out; + } + + /** + * Projects each element of a sequence into a new form. + * + * @param + * The type of the projected values + * @param selector + * - A transform function to apply to each element. + * @return A List whose elements are the result of invoking the transform + * function on each element of the sequence. + */ + public default BetterList select(Function selector) { + BetterList out = new BetterArrayList(); + for (T element : this) + out.add(selector.apply(element)); + return out; + } + + /** + * Bypasses a specified number of elements in the sequence and then returns the + * remaining elements. + * + * @param count + * - The number of elements to skip before returning the remaining + * elements. + * @return a List that contains the elements that occur after the specified + * index in the sequence. + */ + public default BetterList skip(int count) { + BetterList out = new BetterArrayList(); + int n = 0; + for (T element : this) { + if (n >= count) + out.add(element); + n++; + } + return out; + } + + /** + * Bypasses elements in the sequence as long as a specified condition is true + * and then returns the remaining elements. + * + * @param predicate + * - A function to test each element for a condition. + * @return a List that contains the elements from the sequence starting at the + * first element in the linear series that does not pass the test + * specified by predicate. + */ + public default BetterList skipWhile(Function predicate) { + BetterList out = new BetterArrayList(); + boolean match = true; + for (T element : this) + if (!match || !predicate.apply(element)) { + match = false; + out.add(element); + } + return out; + } + + /** + * Computes the sum of the sequence of Double values that are obtained by + * invoking a transform function on each element of the input sequence. + * + * @param selector + * - A transform function to apply to each element. + * @return The sum of the projected values. Zero if the sequence contains no + * elements. + */ + public default Double sum(Function selector) { + double sum = 0d; + for (T element : this) + sum += selector.apply(element); + return sum; + } + + /** + * Returns a specified number of contiguous elements from the start of the + * sequence. + * + * @param count + * - The number of elements to return. + * @return a List that contains the specified number of elements from the start + * of the input sequence. + */ + public default BetterList take(int count) { + BetterList out = new BetterArrayList(); + int n = 0; + for (T element : this) { + if (n < count) + out.add(element); + else + break; + n++; + } + return out; + } + + /** + * Returns elements from the sequence as long as a specified condition is true. + * + * @param predicate + * - A function to test each element for a condition. + * @return a List that contains the elements from the sequence that occur before + * the element at which the test no longer passes. + */ + public default BetterList takeWhile(Function predicate) { + BetterList out = new BetterArrayList(); + for (T element : this) + if (predicate.apply(element)) + out.add(element); + else + break; + return out; + } + + /** + * Produces the set union of two sequences. + * + * @param other + * - Another List whose distinct elements form the second set for the + * union. + * @return A List that contains the elements from both sequences, excluding + * duplicates. + */ + public default BetterList union(List other) { + BetterList out = new BetterArrayList(); + for (T element : this) + if (other.contains(element)) + out.add(element); + return out; + } + + /** + * Filters a sequence of values based on a predicate. + * + * @param predicate + * - A function to test each element for a condition. + * @return a List that contains elements from the sequence that satisfy the + * condition. + */ + public default BetterList where(Function predicate) { + BetterList out = new BetterArrayList(); + for (T element : this) + if (predicate.apply(element)) + out.add(element); + return out; + } + +} diff --git a/src/fr/klemek/betterlists/BetterStack.java b/src/fr/klemek/betterlists/BetterStack.java new file mode 100644 index 0000000..f33c967 --- /dev/null +++ b/src/fr/klemek/betterlists/BetterStack.java @@ -0,0 +1,51 @@ +package fr.klemek.betterlists; + +import java.util.List; +import java.util.Stack; + +/** + * An extension of the java.util.Stack class which include some of the C# LINQ + * useful functions. + * + * @author Klemek + * + * @see java.util.Stack + */ +public class BetterStack extends Stack implements BetterList { + + private static final long serialVersionUID = 5642889973315247461L; + + /** + * Creates an empty Stack. + */ + public BetterStack() { + super(); + } + + /** + * Returns a view of the portion of this list between the specified fromIndex, + * inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the + * returned list is empty.) The returned list is backed by this list, so + * non-structural changes in the returned list are reflected in this list, and + * vice-versa. The returned list supports all of the optional list operations + * supported by this list. This method eliminates the need for explicit range + * operations (of the sort that commonly exist for arrays). Any operation that + * expects a list can be used as a range operation by passing a subList view + * instead of a whole list. (see List.subList) + * + * @param fromIndex + * - low endpoint (inclusive) of the subList + * @param toIndex + * - high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException + * for an illegal endpoint index value (fromIndex < 0 || toIndex > + * size || fromIndex > toIndex) + * @see java.util.List + */ + @Override + public BetterStack subList(int fromIndex, int toIndex) { + return (BetterStack) ((List) this).subList(fromIndex, toIndex); + } + +} diff --git a/src/fr/klemek/betterlists/BetterVector.java b/src/fr/klemek/betterlists/BetterVector.java new file mode 100644 index 0000000..fddf1bf --- /dev/null +++ b/src/fr/klemek/betterlists/BetterVector.java @@ -0,0 +1,100 @@ +package fr.klemek.betterlists; + +import java.util.Collection; +import java.util.List; +import java.util.Vector; + +/** + * An extension of the java.util.Vector class which include some of the C# LINQ + * useful functions. + * + * @author Klemek + * + * @see java.util.Vector + */ +public class BetterVector extends Vector implements BetterList { + + private static final long serialVersionUID = -704157461726911759L; + + /** + * Constructs a vector containing the elements of the specified collection, in + * the order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this vector + */ + public static BetterVector fromList(Collection c) { + return new BetterVector(c); + } + + /** + * Constructs an empty vector so that its internal data array has size 10 and + * its standard capacity increment is zero. + */ + public BetterVector() { + super(); + } + + /** + * Constructs a vector containing the elements of the specified collection, in + * the order they are returned by the collection's iterator. + * + * @param c + * - the collection whose elements are to be placed into this vector + */ + public BetterVector(Collection c) { + super(c); + } + + /** + * Constructs an empty vector with the specified initial capacity and with its + * capacity increment equal to zero. + * + * @param initialCapacity + * - the initial capacity of the vector + */ + public BetterVector(int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs an empty vector with the specified initial capacity and capacity + * increment. + * + * @param initialCapacity + * - the initial capacity of the vector + * @param capacityIncrement + * - the amount by which the capacity is increased when the vector + * overflows + */ + public BetterVector(int initialCapacity, int capacityIncrement) { + super(initialCapacity, capacityIncrement); + } + + /** + * Returns a view of the portion of this list between the specified fromIndex, + * inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the + * returned list is empty.) The returned list is backed by this list, so + * non-structural changes in the returned list are reflected in this list, and + * vice-versa. The returned list supports all of the optional list operations + * supported by this list. This method eliminates the need for explicit range + * operations (of the sort that commonly exist for arrays). Any operation that + * expects a list can be used as a range operation by passing a subList view + * instead of a whole list. (see List.subList) + * + * @param fromIndex + * - low endpoint (inclusive) of the subList + * @param toIndex + * - high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException + * for an illegal endpoint index value (fromIndex < 0 || toIndex > + * size || fromIndex > toIndex) + * @see java.util.List + */ + @Override + public BetterVector subList(int fromIndex, int toIndex) { + return (BetterVector) ((List) this).subList(fromIndex, toIndex); + } + +} diff --git a/test/fr/klemek/betterlists/BetterListsTests.java b/test/fr/klemek/betterlists/BetterListsTests.java new file mode 100644 index 0000000..8f9e90a --- /dev/null +++ b/test/fr/klemek/betterlists/BetterListsTests.java @@ -0,0 +1,334 @@ +package fr.klemek.betterlists; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import org.junit.Assert; +import org.junit.Test; + +public class BetterListsTests { + + protected class Dummy { + double d; + String s; + + public Dummy(double d, String s) { + this.d = d; + this.s = s; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Dummy other = (Dummy) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (Double.doubleToLongBits(d) != Double.doubleToLongBits(other.d)) + return false; + if (s == null) { + if (other.s != null) + return false; + } else if (!s.equals(other.s)) + return false; + return true; + } + + private BetterListsTests getOuterType() { + return BetterListsTests.this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + long temp; + temp = Double.doubleToLongBits(d); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + ((s == null) ? 0 : s.hashCode()); + return result; + } + } + + @Test + public void testAll() { + ArrayList al = new ArrayList(); + al.add(new Dummy(1d,"hello")); + al.add(new Dummy(2d,"test")); + al.add(new Dummy(2d,"hello")); + + BetterArrayList bal = BetterArrayList.fromList(al); + + Assert.assertTrue(bal.all(du -> du.d > 0)); + Assert.assertFalse(bal.all(du -> du.d > 1)); + } + + @Test + public void testAny() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(2d,"hello")); + + Assert.assertTrue(bal.any(du -> du.s.startsWith("t"))); + Assert.assertFalse(bal.any(du -> du.s.startsWith("b"))); + } + + @Test + public void testCount() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(2d,"hello")); + + Assert.assertEquals(3, bal.count()); + Assert.assertEquals(2, bal.count(du -> du.s.length() > 4)); + } + + @Test + public void testExclude() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"test")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + + BetterArrayList bal2 = new BetterArrayList(); + bal2.add(new Dummy(2d,"test")); + bal2.add(new Dummy(3d,"hello")); + bal2.add(new Dummy(5d,"test")); + + BetterArrayList bal3 = (BetterArrayList) bal1.exclusion(bal2); + Assert.assertEquals(2, bal3.size()); + Assert.assertEquals(bal1.get(0), bal3.get(0)); + Assert.assertEquals(bal1.get(3), bal3.get(1)); + } + + @Test + public void testFirst() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(2d,"hello")); + + Assert.assertEquals(bal.get(0), bal.first(du -> du.s.startsWith("h"))); + + try { + bal.first(du -> du.s.startsWith("d")); + Assert.fail("no error"); + } catch (NoSuchElementException e) { + } + + Assert.assertEquals(bal.get(0), bal.firstOrDefault(du -> du.s.startsWith("h"), new Dummy(3d,"default"))); + + Assert.assertEquals(new Dummy(3d,"default"), bal.firstOrDefault(du -> du.s.startsWith("d"), new Dummy(3d,"default"))); + } + + @Test + public void testLast() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(2d,"hello")); + + Assert.assertEquals(bal.get(2), bal.last(du -> du.s.startsWith("h"))); + + try { + bal.last(du -> du.s.startsWith("d")); + Assert.fail("no error"); + } catch (NoSuchElementException e) { + } + + Assert.assertEquals(bal.get(2), bal.lastOrDefault(du -> du.s.startsWith("h"), new Dummy(3d,"default"))); + + Assert.assertEquals(new Dummy(3d,"default"), bal.lastOrDefault(du -> du.s.startsWith("d"), new Dummy(3d,"default"))); + } + + @Test + public void testMax() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(3d,"hello2")); + + Assert.assertEquals(6d, bal.max(du -> (double)du.s.length()), 0.001d); + } + + @Test + public void testMean() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(3d,"hello2")); + + Assert.assertEquals(5d, bal.mean(du -> (double)du.s.length()), 0.001d); + } + + @Test + public void testMin() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(3d,"hello2")); + + Assert.assertEquals(4d, bal.min(du -> (double)du.s.length()), 0.001d); + } + + @Test + public void testOrderBy() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello1")); + bal1.add(new Dummy(2d,"hello2")); + bal1.add(new Dummy(3d,"hello0")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello4")); + + BetterArrayList bal2 = (BetterArrayList) bal1.orderBy(c -> c.s); + Assert.assertNotEquals(bal1, bal2); + Assert.assertEquals(bal1.get(2), bal2.get(0)); + Assert.assertEquals(bal1.get(0), bal2.get(1)); + Assert.assertEquals(bal1.get(1), bal2.get(2)); + Assert.assertEquals(bal1.get(4), bal2.get(3)); + Assert.assertEquals(bal1.get(3), bal2.get(4)); + } + + @Test + public void testOrderByDescending() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello1")); + bal1.add(new Dummy(2d,"hello2")); + bal1.add(new Dummy(3d,"hello0")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello4")); + + BetterArrayList bal2 = (BetterArrayList) bal1.orderByDescending(c -> c.d); + Assert.assertNotEquals(bal1, bal2); + for(int i = 0; i < 5; i++) + Assert.assertEquals(bal1.get(4-i), bal2.get(i)); + } + + @Test + public void testReverse() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"hello")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello")); + + BetterArrayList bal2 = (BetterArrayList) bal1.reverse(); + Assert.assertEquals(5, bal2.size()); + for(int i = 0; i < 5; i++) + Assert.assertEquals(bal1.get(i), bal2.get(4-i)); + } + + @Test + public void testSelect() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"hello")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello")); + + BetterArrayList bal2 = (BetterArrayList) bal1.select(du -> du.d); + Assert.assertEquals(5, bal2.size()); + for(int i = 0; i < 5; i++) + Assert.assertEquals(bal1.get(i).d, bal2.get(i), 0.0001); + } + + @Test + public void testSkip() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"hello")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello")); + + Assert.assertEquals(bal1, bal1.skip(0)); + Assert.assertEquals(0, bal1.skip(10).size()); + + BetterArrayList bal2 = (BetterArrayList) bal1.skip(2); + Assert.assertEquals(3, bal2.size()); + for(int i = 0; i < 3; i++) + Assert.assertEquals(bal1.get(i+2), bal2.get(i)); + + BetterArrayList bal3 = (BetterArrayList) bal1.skipWhile(du -> du.s.startsWith("h")); + Assert.assertEquals(2, bal3.size()); + for(int i = 0; i < 2; i++) + Assert.assertEquals(bal1.get(i+3), bal3.get(i)); + } + + @Test + public void testSum() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(3d,"hello2")); + + Assert.assertEquals(6d, bal.sum(du -> du.d), 0.001d); + } + + @Test + public void testTake() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"hello")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + bal1.add(new Dummy(5d,"hello")); + + Assert.assertEquals(bal1, bal1.take(10)); + + Assert.assertEquals(0, bal1.take(0).size()); + + BetterArrayList bal2 = (BetterArrayList) bal1.take(2); + Assert.assertEquals(2, bal2.size()); + for(int i = 0; i < 2; i++) + Assert.assertEquals(bal1.get(i), bal2.get(i)); + + BetterArrayList bal3 = (BetterArrayList) bal1.takeWhile(du -> du.s.startsWith("h")); + Assert.assertEquals(3, bal3.size()); + for(int i = 0; i < 3; i++) + Assert.assertEquals(bal1.get(i), bal3.get(i)); + } + + @Test + public void testUnion() { + BetterArrayList bal1 = new BetterArrayList(); + bal1.add(new Dummy(1d,"hello")); + bal1.add(new Dummy(2d,"test")); + bal1.add(new Dummy(3d,"hello")); + bal1.add(new Dummy(4d,"test")); + + BetterArrayList bal2 = new BetterArrayList(); + bal2.add(new Dummy(2d,"test")); + bal2.add(new Dummy(3d,"hello")); + bal2.add(new Dummy(5d,"test")); + + BetterArrayList bal3 = (BetterArrayList) bal1.union(bal2); + Assert.assertEquals(2, bal3.size()); + Assert.assertEquals(bal1.get(1), bal3.get(0)); + Assert.assertEquals(bal1.get(2), bal3.get(1)); + } + + @Test + public void testWhere() { + BetterArrayList bal = new BetterArrayList(); + bal.add(new Dummy(1d,"hello")); + bal.add(new Dummy(2d,"test")); + bal.add(new Dummy(3d,"hello")); + + BetterArrayList bal2 = (BetterArrayList) bal.where(du -> du.s.startsWith("h")); + + Assert.assertEquals(2, bal2.size()); + Assert.assertEquals(new Dummy(1d,"hello"), bal2.get(0)); + Assert.assertEquals(new Dummy(3d,"hello"), bal2.get(1)); + } +}