迭代列表,修改每个元素:有更快的方法吗?

时间:2013-09-09 10:24:42

标签: java list

我有List String个,我想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;

对于大型列表,是否有更有效的方法可以做到这一点?

5 个答案:

答案 0 :(得分:14)

不,你很好。它的效率和它一样高效。没有魔法可以避免迭代。

要记住一点,但是:如果listToTrim不是随机访问列表(即它实现RandomAccess),然后使用Iterator(或内部使用Iterator的增强型for循环)而不是传统的for循环通常更有效。不显示List的最值得注意的RandomAccessLinkedList。在l.get(300)上使用600个元素调用LinkedList将需要遍历~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());
    }
}

答案 1 :(得分:3)

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

答案 2 :(得分:3)

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

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

答案 3 :(得分: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

答案 4 :(得分: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()基本上做同样的事情,也懒得。

List<String> trimmedList = Lists.transform(list, new Function<String, String>() {
    @Override
    public String apply(String input) {
        return input.trim();
    }
});