2

我有三个List<String>变量:classFilesusernamesfileDirectories。我有一个String(字符串列表,但我会将列表中的每个字符串与下面的循环进行比较),它由每个列表中的一个项目组成。我想遍历所有三个列表并检查所有三个列表中的一个值是否在字符串中

解决此问题的最佳方法是什么?

for(String classFile:classFiles) {
//if contains classfile statement
  for(String username:usernames) {
  //if contains username statement
    for(String fileDirectory:fileDirectories) {
      //if contains filedirectory statement
    }
  }
}

或者

for(String classFile:classFiles) {
  for(String username:usernames) {
    for(String fileDirectory:fileDirectories) {
      //if statement
    }
  }
}

或者

for(String classFile:classFiles) {
  //make list of files that contain classFile
}

for(String username:usernames) {
  //remove items from list that do not contain username
}

for(String fileDirectory:fileDirectories){
  //remove items from list that do not contain fileDirectory
}

还是有更好的方法来做到这一点?

编辑:示例

classFiles - a1, a2, a3
usernames - noc1, noc2, noc3
fileDirectories - C:/projects/a1/noc1/example.java, C:/projects/a1/ad3/example.java

和要检查的字符串

String - C:/bin/a1/noc1/example.class

我想要做的是如果fileDirectory和String都包含一个classFile和用户名,然后将它添加到一个列表中

所以在这个例子C:/bin/a1/noc1/example.class中将被添加到列表中,但C:/bin/a4/fd1/example.class不会或C:/bin/a3/noc3/example.class不会被添加

4

4 回答 4

9

当您对每个循环执行删除操作时,这不是最佳选择。您应该在迭代器上使用 Iterator 和 remove 以避免并发修改异常。

反而

for(String fileDirectory:fileDirectories){
  //remove items from list that do not contain fileDirectory
}

你应该做类似的事情

Iterator iter = fileDirectores.iterator();
while(iter.hasNext())
{
//Get next
//Do your check 
iter.remove();
}

这导致有三个单独的迭代来完全满足您的要求。

于 2012-09-11T15:21:04.170 回答
1

有时最好定义您实际尝试编写的函数:

/**
  * Checks to see if candidate has one string in each of classFiles, usernames and fileDirectories
  */ 
public boolean hasEssentialComponents(List<String> candidate) {
  //Code here
}

现在,您的第一个选项具有非常长的最大运行时间 O(n^3)。如果您希望该函数通常会失败,这意味着对于您的三个列表中的每个项目,您正在循环遍历下一个列表。其中大部分是多余的,如果这些列表很长,您将对性能产生巨大影响。

第二个略有不同,但总运行时间相同。

第三个显然更好;在这种情况下,一旦您发现列表没有组件并且您从不检查列表中的组件两次,您就会失败。然而,Java 提供了一些可以使这更容易的糖。

public boolean hasEssentialComponents(List<String> candidates) {
  //Sanity check the data
  if (candidate.size() != 3) { return false; } //I'm assuming a 'good' candidate has only three items.

  valid = true;
  for (String candidate:candidates) {
    if (valid &&  
        ! (   check(this.classFiles, candidate)
           || check(this.usernames, candidate)
           || check(this.fileDirectories, candidate) )
          )) {
      valid = false;
    }
  }
  return valid;
}

private boolean check(List<String> masterList, String candidate) {
  return masterList.contains(candidate);
}

现在,我在这里不必要地冗长,以确保梳理出问题的各个部分。请注意,您应该尽可能使用 Java 内置函数;他们优化得很好。不要把你的清单加在一起;您正在花费不必要的时间进行复制。此外,如果您只需要这样,请只进行一次比较:请注意,如果您知道字符串列表中的元素应该在您的主列表中的哪个位置,则可以做得更好。

最后,我真的建议你先写一个方法签名。它迫使你思考你真正想要做什么。

于 2012-09-11T15:35:51.357 回答
0

所以我认为你想得到所有三个列表之间的交集?只需使用retainAllList 上的方法。

classFiles.retainAll(usernames);
classFiles.retainAll(fileDirectories);

现在classFiles将只有所有三个列表之间的交集。

于 2012-09-11T15:26:21.937 回答
0

您可以考虑使用 HashSet 或 HashMap 来快速访问您的字符串值(使用 .contains(string))吗?

它将消除循环。

如果我能很好地理解问题,我会这样做(不确定^^)

于 2012-09-11T15:35:18.007 回答