反对意见';用Java创建列表
假设我有一个反对意见';用Java创建列表,java,collections,list,guava,Java,Collections,List,Guava,假设我有一个java.util.List列表,我想通过在List的开头添加一个元素e来创建一个新的List(也就是说,我想对比e和List)。例如,如果列表为 [1,2,3,4] 而e是5,则cons(e,list)将是 [5,1,2,3,4] 可以共享list和cons(e,list)的元素,但不应修改list 实施cons的最简单和/或最有效的方法是什么?结果是不可修改的。允许使用谷歌收藏库 如果list是一个com.google.common.collect.ImmutableList
java.util.List列表
,我想通过在List
的开头添加一个元素e
来创建一个新的List
(也就是说,我想对比e
和List
)。例如,如果列表
为
[1,2,3,4]
而e
是5
,则cons(e,list)
将是
[5,1,2,3,4]
可以共享list
和cons(e,list)
的元素,但不应修改list
实施cons
的最简单和/或最有效的方法是什么?结果是不可修改的。允许使用谷歌收藏库
如果list
是一个com.google.common.collect.ImmutableList
,你能用一个吗
这不会受到其中一个参数是否不可变以及是否仍由原始集合c1和c2支持的影响
如果您需要列表
,我可能会执行以下操作:
public List cons(Collection c1, Collection c2)
{
ArrayList cons = new ArrayList(c1.size() + c2.size());
cons.addAll(c1);
cons.addAll(c2);
return cons;
}
公共静态列表cons(列表列表,T){
ArrayList结果=新建ArrayList(列表);
结果:添加(0,t);
返回结果;
}
根据评论编辑:
因为问题是“实现cons的最简单和/或最有效的方法”,所以我选择了“最简单”。如果知道有更有效的方法,我不会感到惊讶。将元素放在列表之前是另一种有效的方法,最初分配正确的大小可能会提高性能。过早优化是万恶之源。提供了那种Lisp-y的东西。虽然大多数人都想使用Clojure作为语言(和我一样),但Clojure库都是真正的Java代码,如果您愿意,您可以将Java中的数据结构用作一个特殊的库。这样你就有能力做反义词之类的事情,你就有了Clojure使用的不变性。Clojure数据结构也实现了等效的Java类型
只是从另一个角度考虑。我要拿出我的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;
}
当然,LinkedList将是在列表开头插入项目的最有效方式
只需使用Java附带的类,因为您提到了
cons
函数,我假设您正在使用由cons
单元格组成的链表的概念模型来解决这个问题。具体来说,我假设您认为每个列表都有一个car
(第一个元素)和一个cdr
(包含以下所有元素的子列表)
Java支持链接列表,如Java.util.LinkedList
。这些工具适用于线性遍历,可以非常有效地插入元素。这些与我上面提到的链表最为相似
Java还提供了Java.util.ArrayList
。这类列表适用于随机访问,但在插入元素时速度可能较慢。事实上,在列表开头插入元素时,它们的速度最慢。由于ArrayList
s在后台实现为数组,因此必须将每个元素在列表中向前复制一个位置,以便为新的第一个元素腾出空间。现在,如果您碰巧还需要一个更大的数组,ArrayList
将分配一个新数组,复制所有元素,依此类推
(谷歌的ImmutableList
被称为“随机访问”,因此它可能更类似于后者。)
如果您计划经常使用cons
方法,我建议将其用于链接列表。cons
操作实质上是在列表的开头添加一个元素。这对于线性结构(如阵列)没有什么意义。出于这个原因,我建议不要使用数组列表:它们在概念上不适合这个任务
对于非常挑剔的人:因为每次调用cons
时都会返回一个新列表,所以无论该列表是LinkedList
还是ArrayList
,都必须进行复制。然而,cons
操作的全部原理是它在链表上操作
public LinkedList cons(电子汽车,列表cdr){
LinkedList目的地=新的LinkedList(cdr);
目的地:第一站(汽车);
返回目的地;
}
请注意,上述代码是在阅读了上述答案后编写的,因此我为任何意外抄袭行为道歉。如果你看到了,请告诉我,我会向你表示感谢
假设您对返回一个
LinkedList
感到满意,那么在本例中,您可以使用ImmutableList
作为cdr
。另一个变体,如果您只有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;
}
公共静态列表cons(E、iter){
列表=新的ArrayList();
列表.添加(e);
对于(e2:iter)列表,添加(e2);
退货清单;
}
公共静态列表cons(Iterable…iters){
列表=新的ArrayList();
用于(iter:iters)用于(e1:iter1)列表。添加(e1);
退货清单;
}
我相信您真正想要的答案是:
该方法甚至被称为cons
我对这个图书馆没有经验。前几天刚听说的。我希望它是好的 一个有效的解决方案是创建自己的列表实现,惰性地委托。如果不可修改,也不会太麻烦。如果是通过工厂方法创建的,那么您甚至可以使用两种不同的底层实现之一,具体取决于参数列表是否实现了随机访问 对于最简单的情况(未检查是否编译,未进行健全性检查等):
class ConsList扩展了AbstractList
{
私人决赛E优先;
私人最终名单;
ConsList(E优先,列表剩余)
{
this.first=first;
这个。休息=休息;
}
公共整数获取(整数索引)
{
返回(索引)
<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;
}
<E> ImmutableList<E> cons(E e, ImmutableList<E> list) {
return ImmutableList.<E>builder()
.add(e)
.addAll(list)
.build();
}
public <E> LinkedList<E> cons(E car, List<E> cdr) {
LinkedList<E> destination = new LinkedList<E>(cdr);
destination.addFirst(car);
return destination;
}
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;
}
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;
}
}
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());