/* * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to <http://unlicense.org/> */ package java.util; import java.util.function.Function; import java.util.function.PredicateEx; import jxtn.core.axi.comparators.MemberComparators; import jxtn.core.axi.util.BinarySearchResult; /** * {@link List}的延伸功能。 * * @author AqD * @param <E> 清單項目型態 */ public interface ListExt<E> extends CollectionExt<E> { /** * 二元搜尋位置並插入,目標需實作{@link Comparable}。 * * @param item 要插入的目標 */ default void binaryInsert(E item) { @SuppressWarnings("unchecked") Comparable<? super E> comparable = (Comparable<? super E>) item; List<E> thiz = (List<E>) this; BinarySearchResult result = this.binarySearch(comparable); thiz.add(result.getIndex(), item); } /** * 二元搜尋,用指定的函數計算排序用鍵值。 * * @param <K> 代表項目的鍵值型態 * @param getKey 取得項目鍵值的函數,清單本身須已用該鍵值進行排序 * @param key 要搜尋的目標鍵值 * @return 搜尋結果 */ default <K extends Comparable<? super K>> BinarySearchResult binarySearch(Function<? super E, ? extends K> getKey, K key) { Objects.requireNonNull(getKey); List<E> thiz = (List<E>) this; int low = 0; int high = thiz.size() - 1; while (low <= high) { int mid = (low + high) >>> 1; E midVal = thiz.get(mid); K midKey = getKey.apply(midVal); Comparable<? super K> midKeyCmp = midKey; int cmp = midKeyCmp.compareTo(key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return new BinarySearchResult(true, mid); } } return new BinarySearchResult(false, low); } /** * 二元搜尋,用指定的函數計算排序用鍵值。 * * @param <K> 代表項目的鍵值型態 * @param getKey 取得項目鍵值的函數,清單本身須已用該鍵值進行排序 * @param key 要搜尋的目標鍵值 * @param comparator 比較鍵值的{@link Comparator} * @return 搜尋結果 */ default <K> BinarySearchResult binarySearch(Function<? super E, ? extends K> getKey, K key, Comparator<K> comparator) { Objects.requireNonNull(getKey); List<E> thiz = (List<E>) this; int low = 0; int high = thiz.size() - 1; while (low <= high) { int mid = (low + high) >>> 1; E midVal = thiz.get(mid); K midKey = getKey.apply(midVal); int cmp = comparator.compare(midKey, key); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return new BinarySearchResult(true, mid); } } return new BinarySearchResult(false, low); } /** * 二元搜尋,目標需實作{@link Comparable}。 * * @param item 要搜尋的目標 * @return 搜尋結果 */ default BinarySearchResult binarySearch(Comparable<? super E> item) { Objects.requireNonNull(item); List<E> thiz = (List<E>) this; int low = 0; int high = thiz.size() - 1; while (low <= high) { int mid = (low + high) >>> 1; E midVal = thiz.get(mid); int cmp = -item.compareTo(midVal); if (cmp < 0) { low = mid + 1; } else if (cmp > 0) { high = mid - 1; } else { return new BinarySearchResult(true, mid); } } return new BinarySearchResult(false, low); } /** * 依照鍵值排序目前的清單。 * * @param <V> 排序用的鍵值型態 * @param getKey 用作排序的鍵值計算函數 */ default <V extends Comparable<? super V>> void sort(Function<? super E, V> getKey) { Objects.requireNonNull(getKey); List<E> thiz = (List<E>) this; thiz.sort(MemberComparators.byComparable(getKey)); } ////////////////////////////////////////////////////////////////////////// // 泛型方法 // /** * 泛型版本的{@link List#indexOf}。 * * @param e 要檢查索引的項目 * @return 第一個值等於{@code e}的項目索引,或是-1表示找不到 */ @SuppressWarnings("deprecation") default int indexOf2(E e) { List<E> thiz = (List<E>) this; return thiz.indexOf(e); } /** * 泛型版本的{@link List#lastIndexOf}。 * * @param e 要檢查索引的項目 * @return 最後一個值等於{@code e}的項目索引,或是-1表示找不到 */ @SuppressWarnings("deprecation") default int lastIndexOf2(E e) { List<E> thiz = (List<E>) this; return thiz.lastIndexOf(e); } ////////////////////////////////////////////////////////////////////////// // 項目挑選 // /** * 取得第一筆項目。 * * @return 第一筆項目 * @throws NoSuchElementException 沒有項目 */ @Override default E first() { List<E> thiz = (List<E>) this; if (thiz.size() == 0) { throw new NoSuchElementException(); } else { return thiz.get(0); } } /** * 取得第一筆項目。 * * @return 第一筆項目,或null表示沒有項目 */ @Override default E firstOrNull() { List<E> thiz = (List<E>) this; if (thiz.size() == 0) { return null; } else { return thiz.get(0); } } /** * 取得符合指定條件的第一個項目索引。 * * @param <TException> 測試條件可拋出的例外型態 * @param condition 測試條件的函數 * @return 符合{@code filter}的第一個項目索引,或-1表示找不到 * @throws TException 表示{@code condition}丟出例外 */ default <TException extends Exception> int firstIndexOf(PredicateEx<? super E, TException> condition) throws TException { List<E> thiz = (List<E>) this; for (int i = 0; i < thiz.size(); i++) { E e = thiz.get(i); if (condition.testEx(e)) { return i; } } return -1; } /** * 取得第N筆項目。 * * @param position 位置 * @return 第N筆項目 * @throws NoSuchElementException 沒有第N筆項目 */ @Override default E getNth(int position) { List<E> thiz = (List<E>) this; if (position >= thiz.size()) { throw new NoSuchElementException(Integer.toString(position)); } return thiz.get(position); } /** * 取得第N筆項目或null。 * * @param position 位置 * @return 第N筆項目,或null表示沒有第N筆項目 */ @Override default E getNthOrNull(int position) { List<E> thiz = (List<E>) this; if (position >= thiz.size()) { return null; } return thiz.get(position); } /** * 取得最後一筆項目。 * * @return 最後一筆項目 * @throws NoSuchElementException 沒有項目 */ @Override default E last() { List<E> thiz = (List<E>) this; if (thiz.size() == 0) { throw new NoSuchElementException(); } else { return thiz.get(thiz.size() - 1); } } /** * 取得符合條件的最後一筆項目。 * * @param <TException> 測試條件可拋出的例外型態 * @param condition 取得項目的條件測試函數 * @return 最後一筆項目 * @throws NoSuchElementException 沒有最後一筆或符合條件的項目 * @throws TException 表示{@code condition}丟出例外 */ @Override default <TException extends Exception> E last(PredicateEx<? super E, ? extends TException> condition) throws TException { List<E> thiz = (List<E>) this; for (int i = thiz.size() - 1; i >= 0; i--) { E item = thiz.get(i); if (condition.testEx(item)) { return item; } } throw new NoSuchElementException(); } /** * 取得最後一筆項目或null。 * * @return 最後一筆項目,或null表示沒有項目 */ @Override default E lastOrNull() { List<E> thiz = (List<E>) this; if (thiz.size() == 0) { return null; } else { return thiz.get(thiz.size() - 1); } } /** * 取得符合條件的最後一筆項目或null。 * * @param <TException> 測試條件可拋出的例外型態 * @param condition 取得項目的條件測試函數 * @return 最後一筆項目,或null表示沒有符合條件的項目 * @throws TException 表示{@code condition}丟出例外 */ @Override default <TException extends Exception> E lastOrNull(PredicateEx<? super E, ? extends TException> condition) throws TException { List<E> thiz = (List<E>) this; for (int i = thiz.size() - 1; i >= 0; i--) { E item = thiz.get(i); if (condition.testEx(item)) { return item; } } return null; } }