在没有外部库的情况下就地筛选Java列表
这个问题类似于“基于谓词过滤a在没有外部库的情况下就地筛选Java列表,java,list,collections,java-7,Java,List,Collections,Java 7,这个问题类似于“基于谓词过滤ajava.util.Collection” 由于列表较大,因此无法在适当的位置完成筛选(O(1)memory,不包括输入) 不得使用外部库(即Guava、Apache commons等) Java 7兼容(无Java 8流) 我们可以假设java.util.Collection类型是实现.remove(int)的java.util.List 可能的解决办法: 在列表的迭代器上使用.remove()方法。这可能引发不支持操作异常,因为迭代器上可选地支持.remo
java.util.Collection
”
- 由于列表较大,因此无法在适当的位置完成筛选(
memory,不包括输入)O(1)
- 不得使用外部库(即Guava、Apache commons等)
- Java 7兼容(无Java 8流)
java.util.Collection
类型是实现.remove(int)
的java.util.List
可能的解决办法:
- 在
列表的
迭代器上使用
方法。这可能引发.remove()
,因为不支持操作异常
迭代器上可选地支持
方法.remove()
- 编写我们自己的迭代器,使用索引
和.size()
遍历列表.remove(int)
是
Iterator.remove()
您可以使用包装的迭代器来伪造过滤器,并使其与对象一起工作(类似于Prediates的实现方式);然而,还有一些次要问题:
您声明列表非常大,解决方案的内存影响应该是O(1)
,但是如果不知道正在操作的列表,就无法保证这一点。remove(int)
操作符可以在实现中分配一个新的列表索引并复制到其中
假设列表不做这样的事情,最好实现自己的迭代器,它接受类似谓词的测试,或者编写一个特定的循环来处理列表
无论如何,这听起来像是一个面试问题。这里有一个例子
public interface MyPredicate<T> {
public boolean isTrue(T value);
}
public void removeOnTrue(List<T> list, MyPredicate<T> predicate) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (predicate.isTrue(next)) {
iterator.remove();
}
}
}
公共接口MyPredicate{
公共布尔值(T值);
}
public void removeOnTrue(列表,MyPredicate谓词){
迭代器迭代器=list.Iterator();
while(iterator.hasNext()){
T next=iterator.next();
if(谓词isTrue(下一个)){
iterator.remove();
}
}
}
在索引之间使用for循环也是一样的,只是随后必须跟踪索引(并使用索引删除)
要使用上述示例,请执行以下操作:
...
List<String> names = ...;
removeOnTrue(names, new MyPredicate<String>() {
public boolean isTrue(String value) {
return value.startsWith("A");
}
});
...
。。。
名单名称=。。。;
RemoveOnTue(名称,新的MyPredicate(){
公共布尔值isTrue(字符串值){
返回值。以“A”开头;
}
});
...
将产生一个名称
,其中所有以“a”开头的字符串都被删除。过滤器
和谓词
都是Java8类型,因此如果您不想使用Java8,您需要类似的东西
您可以使用包装的迭代器来伪造过滤器,并使其与对象一起工作(类似于Prediates的实现方式);然而,还有一些次要问题:
您声明列表非常大,解决方案的内存影响应该是O(1)
,但是如果不知道正在操作的列表,就无法保证这一点。remove(int)
操作符可以在实现中分配一个新的列表索引并复制到其中
假设列表不做这样的事情,最好实现自己的迭代器,它接受类似谓词的测试,或者编写一个特定的循环来处理列表
无论如何,这听起来像是一个面试问题。这里有一个例子
public interface MyPredicate<T> {
public boolean isTrue(T value);
}
public void removeOnTrue(List<T> list, MyPredicate<T> predicate) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (predicate.isTrue(next)) {
iterator.remove();
}
}
}
公共接口MyPredicate{
公共布尔值(T值);
}
public void removeOnTrue(列表,MyPredicate谓词){
迭代器迭代器=list.Iterator();
while(iterator.hasNext()){
T next=iterator.next();
if(谓词isTrue(下一个)){
iterator.remove();
}
}
}
在索引之间使用for循环也是一样的,只是随后必须跟踪索引(并使用索引删除)
要使用上述示例,请执行以下操作:
...
List<String> names = ...;
removeOnTrue(names, new MyPredicate<String>() {
public boolean isTrue(String value) {
return value.startsWith("A");
}
});
...
。。。
名单名称=。。。;
RemoveOnTue(名称,新的MyPredicate(){
公共布尔值isTrue(字符串值){
返回值。以“A”开头;
}
});
...
将生成一个名称
,删除所有以“a”开头的字符串。没有适合所有列表
s的最佳解决方案,这是您永远无法达到Java 8效率的地方,因为作为接口
方法,Java8的default
方法可以被任何List
实现覆盖,该实现为特定类定制了一个实现
当您想要在Java8之前的版本中合理地实现类似的功能时,您必须关注常见的情况。JRE提供的列表中几乎没有remove(int)
有效的列表,但是Iterator.remove
无效。但是,考虑<<代码> ARAYLIST/<代码>是最常用的可变<代码>列表< /C>实现,对于该实现,基于迭代器的解决方案对于大列表和大量删除的项目表现不佳。这是因为无论您使用的是remove(int)
还是Iterator.remove
,每次删除操作都会将所有后续项移动一个位置,然后才能继续,并且可能会再次删除项。在最坏的情况下,如果谓词匹配所有项,则会产生二次复杂性。因此,为这种情况提供更复杂的解决方案非常重要:
interface Predicate<T> {
boolean test(T object);
}
public static <T> boolean removeIf(List<T> list, Predicate<? super T> p) {
if(list instanceof RandomAccess) {
int num=list.size();
BitSet bs=new BitSet(num);
for(int index=0; index<num; index++) {
if(p.test(list.get(index))) bs.set(index);
}
if(bs.isEmpty()) {
return false;
}
for(int dst=bs.nextSetBit(0), src=dst;; dst++, src++) {
src=bs.nextClearBit(src);
if(src==num) {
list.subList(dst, src).clear();
break;
}
list.set(dst, list.get(src));
}
return true;
}
else {
boolean changed=false;
for(Iterator<T> it=list.iterator(); it.hasNext(); ) {
if(p.test(it.next())) {
it.remove();
changed=true;
}
}
return changed;
}
}
接口谓词{
布尔检验(T对象);
}
public static boolean removeIf(List,Predicate没有适合所有List
s的最佳解决方案,这是您永远无法达到效率的地方