如何获取列表的下三个元素?

3

这个问题更多关于最佳实践而不是从列表中获取元素。

我有一个ArrayList,通过使用简单的for循环进行迭代。如果出现某个关键字,我需要将下面的三个元素与特定模式进行比较。

private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
    for (int i=0; i<fileContent.size(); i++)
    {
        if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
        {
            // get the next three elements of "fileContent" and see if they match a certain pattern
        }
    }
return true;
}

我的第一种方法是在实际的外部循环中再使用另一个for循环,然后将i增加3:

for (int j=i+1; j<=i+3; j++)
{
    if (!fileContent.get(j).matches(PATTERN))
    {
        return false;
    }
}
i+=3;

正如您所看到的,使这个方法做我想要它做的事情并不难,但是......我不确定是否有一种你会称之为更加优美的方法。

4个回答

1

这个问题更多的是关于最佳实践,而不是从列表中获取元素。

在进入细节之前,有几点需要注意:

  • NORMAL.equals(fileContent.get(i)) 而不是 fileContent.get(i).equals(NORMAL) 可以避免出现 NullPointerException
  • 在迭代下三个元素之前,应先检查您的 List 是否有下一个三个元素,以避免出现 ArrayIndexOutOfBoundException

如果只需检查接下来的三个元素,并且只有当其中任何一个元素不匹配模式时才返回false,则可以使用以下代码:
   if (fileContent.size() < i + 3 
    && (!fileContent.get(i+1).matches(PATTERN)
        || !fileContent.get(i+2).matches(PATTERN) 
        || !fileContent.get(i+3).matches(PATTERN))) {
        return false;
   }

这种方法的问题在于它不会检查您的列表是否没有下一个三个元素。
至于您的方法,通过允许检查下一可用元素,您只需在循环之前添加一个条件来检查您的列表是否有下一个元素,然后调用列表上的get方法。您迭代下一个三个元素的方法似乎不错,但需要进行以下改进。
for (int j=i+1; j<=i+3; j++){
    if (fileContent.size() < j && !fileContent.get(j).matches(PATTERN)){
        return false;
    } else {
        break;
    }
}

不需要添加对接下来三个元素的检查,for循环只需到n-3即可,其中n为列表的长度。 - Scorpion
1
谢谢您的输入。现在有很多关于如何解决这个问题的答案,我有点困惑了。 :) 最简单的方法可能是坚持使用内部for循环,但使用流和lambda和/或迭代器看起来很有趣。 - Vulpecula

0
在我看来,你应该编写一个方法,它接受数组和开始查找的索引,并返回布尔值以指示是否匹配三个。这是一种优雅的方式。

0
你可以重复三次,获取元素时使用++i
for (int j = 0; j < 3; j++) {
    if (!fileContent.get(++i).matches(PATTERN)) {
        return false;
    }
}

或者使用流(stream)来实现这样的操作:

if (fileContent.stream().skip(i).limit(3).anyMatch(s -> !s.matches(PATTERN))) {
    return false;
}
i += 3;

但我认为最好的解决方案是完全改变它并使用一个迭代器

private static boolean areVectorArgumentsValid(ArrayList<String> fileContent) {
    for (Iterator<String> it = fileContent.iterator(); it.hasNext();) {
        String s = it.next();
        if (!s.equals(NORMAL) && !s.equals(VERTEX)) {
            continue;
        }
        for (int i = 0; i < 3; i++) {
            if (!it.hasNext() || !it.next().matches(PATTERN)) {
                return false;
            }
        }
    }
    return true;
}

在一般情况下,使用迭代器是否真的更好?迭代器在性能方面如何表现? - Vulpecula
@Vulpecula 这取决于列表的类型。例如,当使用 LinkedList 时,迭代时应始终使用 Iterator,但对于 ArrayList,在性能方面没有太大区别。因此,在这种情况下,您可以使用您认为更易读的那个。 - Bubletan

0

通过引入状态,您可以仅使用一个循环来完成它:

private static boolean areVectorArgumentsValid(ArrayList<String> fileContent)
{
    int state = 0;
    for (int i=0; i<fileContent.size(); i++)
    {
         switch (state) {
         case 0:
             if (fileContent.get(i).equals(NORMAL) || fileContent.get(i).equals(VERTEX))
                 state++;
             break;
         case 1:
         case 2:
         case 3:
             if (!fileContent.get(i).matches(PATTERN))
                 return false;
             state = (state + 1) % 4;
             break;
    }
    return true;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接