6

我有一个Listof Strings,我想要trim()列表的每个元素。

目前,我正在使用ArrayList,对元素进行简单循环,并将修剪后的元素添加到返回列表中,如下所示:

int listLen = listToTrim.size();

List<String> trimmedList = new ArrayList<String>( listLen );

for ( int i = 0; i < listLen; i++ ) {
    trimmedList.add( listToTrim.get( i ).trim() );
}

return trimmedList;

对于大型列表,是否有更有效的方法来执行此操作?

4

5 回答 5

14

不,你很好。这几乎和它一样有效。没有什么魔法可以避免迭代。

有一点要记住,'虽然:如果listToTrim不是一个随机访问列表(即它没有实现RandomAccess),那么使用一个Iterator(或增强的 for 循环,它在Iterator内部使用)而不是传统的 for 循环通常效率更高。最值得注意List的是没有实现RandomAccess的是LinkedList. 调用具有 600 个元素l.get(300)的 aLinkedList将必须遍历 ~300 个元素才能获得正确的元素!

修改代码以使用增强的 for 循环将如下所示:

public List<String> trimStrings(Listy<String> listToTrim) {
    List<String> trimmedList = new ArrayList<String>(listToTrim.size());
    for (String str : listToTrim) {
      trimmedList.add(str.trim());
    }
    return trimmedList;
}

如果不再需要原始列表,那么重新使用原始列表可以节省内存并提高性能:

public void trimStringsInPlace(List<String> listToTrim) {
    ListIterator<String> it = listToTrim.listIterator();
    while (it.hasNext()) {
      it.set(it.next().trim());
    }
}
于 2013-09-09T10:27:50.427 回答
3

此外,您可以使用ArrayList#set()而不是创建新的 ArrayList 。对于较大的列表,这可以显着减少内存占用。

for ( int i = 0; i < listLen; i++ ) {
    listToTrim.set(i,listToTrim.get( i ).trim());
}
于 2013-09-09T10:29:26.260 回答
3

并不真地; 你必须调用trim每个元素,并且预分配ArrayList正确大小的元素是尽可能快的。Java 8 将允许您使语法更紧凑,但迭代和trimming 是这里最少的工作量。

于 2013-09-09T10:28:33.180 回答
3

约阿希姆已经回答了这个问题。但是一个建议——

listToTrim - 当您将项目添加到 listToTrim 时,在添加之前先修剪。这样,您不必为此进行迭代和修改或创建另一个列表。这听起来不合逻辑。

根据评论编辑:

String fruits = "Apple, Banana   , Mango, Passion Fruit, Grapes  ";

List<String> fruitList = Arrays.asList((fruits.trim()).split("\\s*,\\s*")); // Trim first and then regex matches spaces before and after comma

for(String fruit : fruitList){
    System.out.println("Fruit: " + fruit + "\tLength: " + fruit.length());
}

输出:

Fruit: Apple           Length: 5
Fruit: Banana          Length: 6
Fruit: Mango           Length: 5
Fruit: Passion Fruit   Length: 13
Fruit: Grapes          Length: 6
于 2013-09-09T10:31:39.220 回答
3

约阿希姆做对了。那些说你应该在把它们放在第一个列表之前修剪你的字符串的人也说对了。

无论如何,如果后者不适合您,则可能有另一种方法:您确定要使用所有修剪过的字符串吗?或者你会只使用其中的几个,比如说,可能只使用前五个?那么把它们全部修剪掉可能有点过头了。

您可以设计一个特殊的List实现来存储原始列表,但会给出修剪的元素。这就是我的意思:

public class ImmutableStringTrimmingList extends AbstractList<String> {

    private final List<String> stringList;

    public ImmutableStringTrimmingList(List<String> stringList) {
        this.stringList = stringList;
    }

    @Override
    public String get(int index) {
        return stringList.get(index).trim();
    }

    @Override
    public int size() {
        return stringList.size();
    }

}

存储原始列表(因此对该ImmutableStringTrimmingList列表的任何更改也将在此处传播)并String分发延迟修剪的对象。如果您不想做任何不必要的工作,这会很有帮助,因为它只会修剪get(). 它还可以适应缓存修剪过的对象,这样就不必每次都重新修剪它。但如果你觉得这门课对你有帮助,那对你来说是一种练习。


或者,如果你是 Guava 用户,你可以使用Lists.transform()which 基本上做同样的事情,也很懒惰。

List<String> trimmedList = Lists.transform(list, new Function<String, String>() {
    @Override
    public String apply(String input) {
        return input.trim();
    }
});
于 2013-09-09T10:47:34.693 回答