[英]Cons'ing a List in Java
說我有一個java.util.List list
,我想創建一個新的List
中加入元素e
到年初list
(即我想利弊 e
和list
)。 例如,如果list
是
[1,2,3,4]
並且e
是5
,那么cons(e,list)
將是
[5,1,2,3,4]
list
和cons(e,list)
的元素可以共享,但不應修改list
。
實施cons
的最簡單和/或最有效的方法是什么? 結果不可修改是可以的。 允許使用Google Collections Library。
如果list
是com.google.common.collect.ImmutableList
怎么辦?
public static<T> List<T> cons(List<T> list, T t) {
ArrayList<T> result = new ArrayList<T>(list);
result.add(0, t);
return result;
}
編輯回應評論:由於問題是“最簡單和/或最有效的方式來實施利弊”,我選擇了“最簡單”。 我不會驚訝地發現有更有效的方法。 將元素放在列表之前是另一種有效的方法,並且最初分配正確的大小可能會提高性能。 過早優化是萬惡之源。
Clojure提供了那種Lisp-y的東西。 雖然大多數人都認為使用Clojure語言(就像我一樣),但Clojure庫都是真正的Java代碼,如果你願意,你可以使用Java中的數據結構作為一個特殊的庫。 通過這種方式,您可以獲得利弊等等,並獲得Clojure使用的不變性。 Clojure數據strcutres也實現了等效的Java類型。
只是從不同的方向思考。
我相信你真正想要的答案是這樣的:
http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/data/List.html
該方法甚至被稱為cons
。
我沒有這個庫的經驗。 前幾天聽說過它。 我希望這很好!
一個有效的解決方案是創建自己的List實現,懶惰委托。 如果不可修改,那就不會太麻煩了。 如果通過工廠方法創建,那么您甚至可以使用兩個不同的底層實現之一,具體取決於參數List是否實現RandomAccess。
對於最簡單的情況(沒有檢查是否編譯,沒有健全性檢查等):
class ConsList<E> extends AbstractList<E>
{
private final E first;
private final List<E> rest;
ConsList( E first, List<E> rest )
{
this.first = first;
this.rest = rest;
}
public int get( int index )
{
return (index == 0) ? first : rest.get( index - 1 );
}
public int size()
{
return rest.size() + 1;
}
}
我確信其他一些方法可以提高效率,而通過擴展AbstractSequentialList可以更好地滿足順序情況。
這不是眾所周知的,但Sun javac編譯器API包含一個不可變的List實現,它使用append()
和prepend()
等方法返回新的不可變列表。 要使用它,您需要在類路徑上使用tools.jar
,並且需要以下import語句:
import com.sun.tools.javac.util.List;
示例代碼:
final List<Integer> list = List.of(6, 7);
System.out.println(list);
final List<Integer> newList =
list.prepend(5) // this is a new List
.prependList(List.of(1, 2, 3, 4)) // and another new List
.append(8) // and another
.reverse(); // and yet another
System.out.println(newList);
System.out.println(list == newList);
System.out.println(list.getClass());
System.out.println(newList.getClass());
輸出:
6,7
8,7,6,5,4,3,2,1
假
class com.sun.tools.javac.util.List
class com.sun.tools.javac.util.List
我知道這是一個內部API,不應該在生產中使用,但它非常有趣(最后一個感覺正確的java集合)。
注意:顯然, Collection
和List
接口中的所有標准可變方法(如add()
addAll()
)都會拋出UnsupportedOperationException
。
參考:
因為你提到了cons
函數,我將假設你正在使用由cons
單元組成的鏈表的概念模型來解決這個問題。 具體來說,我假設您正在考慮每個列表都有一個car
(第一個元素)和一個cdr
(包含所有后續元素的子列表)。
Java支持鏈表作為java.util.LinkedList
。 這些對於線性遍歷是有益的,並且可以非常有效地插入元素。 這些與我上面提到的鏈表最相似。
Java還提供java.util.ArrayList
。 這種列表適用於隨機訪問,但插入元素時可能會很慢。 實際上,當在列表的開頭插入元素時,它們是最慢的。 因為ArrayList
在幕后實現為數組,所以每個元素必須在列表中向前復制一個位置,以便為新的第一個元素騰出空間。 現在,如果您還需要更大的數組, ArrayList
將分配一個新數組,復制所有元素,依此類推。
(谷歌的ImmutableList
被稱為“隨機訪問”,所以它可能更接近后者。)
如果您打算經常使用cons
方法,我建議將其與鏈表一起使用。 cons
操作實質上是在列表的開頭添加元素。 這對於諸如陣列的線性結構沒有多大意義。 出於這個原因,我建議不要使用數組列表:它們在概念上對於這項工作是錯誤的。
非常挑剔:因為每次調用cons
都會返回一個新列表,無論列表是LinkedList
還是ArrayList
,都必須進行復制。 但是, cons
操作的整個原理是它在鏈表上運行。
public <E> LinkedList<E> cons(E car, List<E> cdr) {
LinkedList<E> destination = new LinkedList<E>(cdr);
destination.addFirst(car);
return destination;
}
請注意,上面的代碼是在閱讀上述答案后編寫的,所以我為任何偶然的抄襲道歉。 讓我知道你是否看到它,我會正確地承認。
假設您對返回LinkedList
感到滿意,可以在此示例中使用ImmutableList
作為cdr
。
你能使用CompositeCollection嗎?
public Collection cons(Collection c1, Collection c2)
{
CompositeCollection cons = new CompositeCollection();
cons.addComposited(c1);
cons.addComposited(c2);
return cons;
}
這不受其中一個參數是否是不可變的影響,並且仍然由原始集合c1和c2支持。
如果你需要一個List
我可能會做以下事情:
public List cons(Collection c1, Collection c2)
{
ArrayList cons = new ArrayList(c1.size() + c2.size());
cons.addAll(c1);
cons.addAll(c2);
return cons;
}
我打算花2美分,然后看看是否有人想出更優雅的東西。 在一般情況下:
<E> List<E> cons(E e, List<E> list) {
List<E> res = Lists.newArrayListWithCapacity(list.size() + 1);
res.add(e);
res.addAll(list);
return res;
}
使用ImmutableList
(不知道這有多高效):
<E> ImmutableList<E> cons(E e, ImmutableList<E> list) {
return ImmutableList.<E>builder()
.add(e)
.addAll(list)
.build();
}
當然,LinkedList是在列表頭部插入項目的最有效方式嗎?
只需使用Java附帶的LinkedList類
另一種變化,如果你只有Iterable。
public static <E> List<E> cons(E e, Iterable<E> iter) {
List<E> list = new ArrayList<E>();
list.add(e);
for(E e2: iter) list.add(e2);
return list;
}
public static <E> List<E> cons(Iterable<E>... iters) {
List<E> list = new ArrayList<E>();
for(Iterable<E> iter: iters) for(E e1: iter1) list.add(e1);
return list;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.