PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/java/core/List.java

http://github.com/pavelfatin/ninety-nine
Java | 260 lines | 208 code | 50 blank | 2 comment | 26 complexity | b798bdb583f102b56d35e3d1bdaf612e MD5 | raw file
Possible License(s): GPL-3.0
  1. package core;
  2. import java.util.Arrays;
  3. import java.util.Iterator;
  4. import java.util.NoSuchElementException;
  5. // A Scala-like immutable List implementation in Java (without higher-order function)
  6. // The performance is not considered in favor of cleaner code (for demo purposes)
  7. public class List<T> implements Iterable<T> {
  8. private static final List NIL = new EmptyList();
  9. private final T _head;
  10. private final List<T> _tail;
  11. private List(T head, List<T> tail) {
  12. _head = head;
  13. _tail = tail;
  14. }
  15. public T head() {
  16. return _head;
  17. }
  18. public List<T> tail() {
  19. return _tail;
  20. }
  21. public boolean isEmpty() {
  22. return false;
  23. }
  24. public boolean nonEmpty() {
  25. return !isEmpty();
  26. }
  27. @Override
  28. public Iterator<T> iterator() {
  29. return new ListIterator<T>(this);
  30. }
  31. @SuppressWarnings("unchecked")
  32. public static <T> List<T> nil() {
  33. return NIL;
  34. }
  35. public static List<Character> listOfChars(String chars) {
  36. List<Character> list = nil();
  37. for (Character each : chars.toCharArray())
  38. list = cons(each, list);
  39. return list.reverse();
  40. }
  41. public static <T> List<T> list(T... elements) {
  42. return list(Arrays.asList(elements));
  43. }
  44. public static <T> List<T> list(Iterable<T> elements) {
  45. List<T> list = nil();
  46. for (T each : elements)
  47. list = cons(each, list);
  48. return list.reverse();
  49. }
  50. public static <T> List<T> singleton(T element) {
  51. return new List<T>(element, List.<T>nil());
  52. }
  53. public static <T> List<T> replicate(int n, T element) {
  54. List<T> list = nil();
  55. for (int i = 0; i < n; i++)
  56. list = cons(element, list);
  57. return list;
  58. }
  59. public static List<Integer> range(int a, int b) {
  60. if (a > b) {
  61. return nil();
  62. } else {
  63. return cons(a, range(a + 1, b));
  64. }
  65. }
  66. public static <T> List<T> cons(T head, List<T> tail) {
  67. return new List<T>(head, tail);
  68. }
  69. public static <T> List<T> concat(List<T> prefix, List<T> suffix) {
  70. List<T> result = suffix;
  71. for (T each : prefix.reverse())
  72. result = cons(each, result);
  73. return result;
  74. }
  75. public List<T> prepend(T head) {
  76. return cons(head, this);
  77. }
  78. public List<T> prepend(List<T> prefix) {
  79. return concat(prefix, this);
  80. }
  81. public List<T> append(List<T> suffix) {
  82. return concat(this, suffix);
  83. }
  84. public List<T> reverse() {
  85. List<T> list = nil();
  86. for (T each : this)
  87. list = cons(each, list);
  88. return list;
  89. }
  90. public int length() {
  91. int c = 0;
  92. for (T each : this)
  93. c++;
  94. return c;
  95. }
  96. public T get(int i) {
  97. int c = 0;
  98. for (T each : this)
  99. if (c == i)
  100. return each;
  101. else
  102. c++;
  103. throw new IndexOutOfBoundsException();
  104. }
  105. public T last() {
  106. if (isEmpty()) throw new NoSuchElementException("List is empty");
  107. T result = null;
  108. for (T each : this)
  109. result = each;
  110. return result;
  111. }
  112. public List<T> take(int i) {
  113. return take(i, this).reverse();
  114. }
  115. public List<T> takeRight(int i) {
  116. return take(i, this.reverse());
  117. }
  118. private static <T> List<T> take(int i, List<T> list) {
  119. List<T> result = nil();
  120. int c = 0;
  121. for (T each : list) {
  122. if (c == i) break;
  123. result = cons(each, result);
  124. c++;
  125. }
  126. return result;
  127. }
  128. public List<T> drop(int i) {
  129. return drop(i, this).reverse();
  130. }
  131. public List<T> dropRight(int i) {
  132. return drop(i, this.reverse());
  133. }
  134. private static <T> List<T> drop(int i, List<T> list) {
  135. List<T> result = nil();
  136. int c = i;
  137. for (T each : list) {
  138. c--;
  139. if (c >= 0) continue;
  140. result = cons(each, result);
  141. }
  142. return result;
  143. }
  144. public List<T> init() {
  145. if (isEmpty()) throw new UnsupportedOperationException("List is empty");
  146. return dropRight(1);
  147. }
  148. public Pair<List<T>, List<T>> splitAt(int index) {
  149. return Pair.pair(take(index), drop(index));
  150. }
  151. @Override
  152. public boolean equals(Object obj) {
  153. if (!(obj instanceof List)) return false;
  154. Iterator ours = this.iterator();
  155. Iterator theirs = ((List) obj).iterator();
  156. while (ours.hasNext() && theirs.hasNext())
  157. if (!ours.next().equals(theirs.next()))
  158. return false;
  159. return !ours.hasNext() && !theirs.hasNext();
  160. }
  161. @Override
  162. public String toString() {
  163. StringBuilder builder = new StringBuilder();
  164. builder.append('[');
  165. Iterator<T> it = iterator();
  166. while (it.hasNext()) {
  167. builder.append(it.next());
  168. if (it.hasNext()) builder.append(", ");
  169. }
  170. builder.append(']');
  171. return builder.toString();
  172. }
  173. private static class EmptyList extends List<Object> {
  174. public EmptyList() {
  175. super(null, null);
  176. }
  177. @Override
  178. public Object head() {
  179. throw new IllegalStateException("Accessing head of the an empty list");
  180. }
  181. @Override
  182. public List<Object> tail() {
  183. throw new IllegalStateException("Accessing tail of the an empty list");
  184. }
  185. @Override
  186. public boolean isEmpty() {
  187. return true;
  188. }
  189. }
  190. private class ListIterator<T> implements Iterator<T> {
  191. private List<T> _list;
  192. public ListIterator(List<T> list) {
  193. _list = list;
  194. }
  195. @Override
  196. public boolean hasNext() {
  197. return !_list.isEmpty();
  198. }
  199. @Override
  200. public T next() {
  201. T value = _list.head();
  202. _list = _list.tail();
  203. return value;
  204. }
  205. @Override
  206. public void remove() {
  207. throw new UnsupportedOperationException();
  208. }
  209. }
  210. }