从 ArrayList 中删除给定长度的字符串?
Posted
技术标签:
【中文标题】从 ArrayList 中删除给定长度的字符串?【英文标题】:Removing Strings of given length from an ArrayList? 【发布时间】:2013-10-27 10:12:16 【问题描述】:我们得到一个 ArrayList 形式的单词列表,如下所示:
public ArrayList<String> getListOfStrings()
ArrayList<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("an");
list.add("exercise");
list.add("to");
list.add("illustrate");
list.add("the");
list.add("use");
list.add("of");
list.add("ArrayLists");
list.add(".");
return list;
如何编写一个方法来删除该列表中的所有单词(即 ArrayList 中的所有对象),这些单词的长度由用户输入“len”?
我已经写了一个方法,列出了用户输入的所有长度为“len”的单词,并且有效,如下:
public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst)
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst)
if(woord.length()==len)
list.add(woord);
return(list);
但作为一个 java 初学者,我被困在如何删除长度为“len”的单词上。请帮忙! (我的印象是您首先从列表的末尾删除它们,就像从后到前一样)
【问题讨论】:
您通过不将它们添加到您返回的新列表中来删除它们。 Backwards 也可以,但只能使用传统的for
循环(属于 for(int i=list.size-1;i>=0;i--)
种类。但首选 AbstractChaos 的解决方案
谢谢,您能详细说明一下吗?我收到一个错误:“大小在 java.util.ArrayList 中具有私有访问权限”更不用说我没有 100% 遵循这段代码中发生的事情(我还是个初学者)
@user2895102 - 这是理查德的一个错字。它应该是list.size()
而不是list.size
。它所做的只是向后循环索引,以确保在删除元素时索引不会搞砸。
【参考方案1】:
您当前遍历列表的方式不允许您在异常情况下将其删除,但迭代器可以。
Iterator<String> it = list.iterator();
while(it.hasNext())
if([Condition])
it.remove();
【讨论】:
你是对的,但分配指定使用上面 Richard Tingle 指定的简单“for”循环:“向后也可以工作,但只能使用传统的 for 循环(for( int i=list.size-1;i>=0;i--) 变种。不过,AbstractChaos 的解决方案更受欢迎——" @user2895102 - 您也可以将上面的循环转换为 for 循环:for (Iterator<String> it = list.iterator(); it.hasNext();) ...
【参考方案2】:
您的方法已经可以用作删除,只需将==
更改为!=
public ArrayList<String> getStringsWithoutEqualLength(int len, ArrayList<String> lijst)
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst)
if(woord.length() != len)
list.add(woord);
return(list);
如果您尝试从lijst
中删除元素,则只需将返回的列表重新分配给它。
ArrayList<String> yourList = ...;
yourList = instance.getStringsWithoutEqualLength(someLength, yourList);
您已经有效地删除了较长的元素,并且比使用Iterator
时做得更快。每次使用 Iterator
删除时,都必须调整后备数组的大小。
【讨论】:
这实际上比使用Iterator
快吗?我会以大致相同的速度钉住它们。 Iterator
应该能够在恒定时间内进行移除,对吧?还是仅适用于链表?
@Cruncher 那是给LinkedList
。 ArrayList$Itr
调用 ArrayList#remove()
为底层数组执行 System.arraycopy
。
@SotiriosDelimanolis 但是你在做什么不是很有效吗?复制 ArrayList 减去 1 与 System.arraycopy 类似,只是您还实例化了更深层次的类?
@AbstractChaos 在此我们只复制一次数组。否则,您必须在每次删除时复制它。
@AbstractChaos 是的,取决于移除的数量。但如果我们在分析 Big-O,这会更快。【参考方案3】:
您必须通过使用Iterator
来从List
中删除值,以防止ConcurrentModificationException
。
List<String> myList = getListOfStrings();
Iterator<String> it = myList.iterator();
while (it.hasNext())
if(it.next().length() == 3)
it.remove();
【讨论】:
【参考方案4】:您甚至可以通过添加布尔参数来使用相同的方法。
public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst, boolean complement)
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst)
if((woord.length()==len) != complement)
list.add(woord);
return(list);
如果您将complement
传递为true
,则如果没有length == len
,则将为您提供所有内容。 complement
和 false
一样会正常运行。
【讨论】:
【参考方案5】:虽然我认为 @SotiriosDelimanolis 的答案可能是您应该使用的,但我还想指出,使用 Java 8,您可以使用 Stream
和 Predicate
轻松完成此操作:
List<String> list2 = list.stream()
.filter(s -> s.length() != 3)
.collect(Collectors.toList());
这是一个完整的测试类:
import java.util.*;
import java.util.stream.*;
class Test
public static void main(String args[])
ArrayList<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("an");
list.add("exercise");
list.add("to");
list.add("illustrate");
list.add("the");
list.add("use");
list.add("of");
list.add("ArrayLists");
list.add(".");
System.out.println(list);
List<String> list2 = list.stream()
.filter(s -> s.length() != 3)
.collect(Collectors.toList());
System.out.println(list2);
和我的测试输出:
$ java Test
[This, is, an, exercise, to, illustrate, the, use, of, ArrayLists, .]
[This, is, an, exercise, to, illustrate, of, ArrayLists, .]
【讨论】:
【参考方案6】:在 Scala 中你会这样做
list.filter(_.length != len)
【讨论】:
在Clojure 中你只需要(remove #(= (count %) len) my-list)
——但 OP 没有询问 Scala 或 Clojure。但是,Java 8 确实 添加了一个 Scala 风格的 stream
包,这是我在回答中使用的。太糟糕了,我们不能指望人们真正拥有 Java 8 一两年...以上是关于从 ArrayList 中删除给定长度的字符串?的主要内容,如果未能解决你的问题,请参考以下文章