Java 我能为这个循环提供更快的性能吗?

Java 我能为这个循环提供更快的性能吗?,java,performance,loops,Java,Performance,Loops,我正在读一本书,删除了其中的一些单词。我的问题是,该过程需要很长时间,我希望使其性能更好(时间更短),例如: Vector<String> pages = new Vector<String>(); // Contains about 1500 page, each page has about 1000 words. Vector<String> wordsToDelete = new Vector<String>(); // Contain

我正在读一本书,删除了其中的一些单词。我的问题是,该过程需要很长时间,我希望使其性能更好(时间更短),例如:

Vector<String> pages = new Vector<String>();  // Contains about 1500 page, each page has about 1000 words.
Vector<String> wordsToDelete = new Vector<String>();  // Contains about 50000 words.

for( String page: pages ) {
    String pageInLowCase = page.toLowerCase();

    for( String wordToDelete: wordsToDelete ) {
        if( pageInLowCase.contains( wordToDelete ) )
            page = page.replaceAll( "(?i)\\b" + wordToDelete + "\\b" , "" );
    }

    // Do some staff with the final page that does not take much time.
}
Vector pages=new Vector();//包含约1500页,每页约1000字。
Vector wordsToDelete=new Vector();//包含大约50000字。
用于(字符串页:页){
字符串pageInLowCase=page.toLowerCase();
for(字符串wordToDelete:wordsToDelete){
if(pageInLowCase.contains(wordToDelete))
page=page.replaceAll(“(?i)\\b”+wordToDelete+”\\b“,”);
}
//做一些工作人员与最后一页,不需要太多的时间。
}

执行此代码大约需要3分钟。如果跳过replaceAll(…)的循环,我可以节省2分钟以上的时间那么有没有一种方法可以更快地执行相同的循环?

首先,您可以去掉
包含(…)
检查。它增加了不必要的开销。有时它会返回真值,但事实并非如此。例如,它将返回
true
表示“not”,即使页面上只有“knot”

另一件事-将
Vector
替换为
ArrayList


正如康拉德在他的评论中指出的,你没有改变向量<代码>字符串是不可变的,因此您不能更改对象。您必须使用
设置(…)
(并维护迭代索引)。

是的,您可以用不同的方式处理页面。基本思路如下

for (String word : page) {
    if (!forbiddenWords.contains(word)) {
        pageResult.append(word);
    }
}
这里是一组禁止使用的单词。
另外,
for(stringword:page)
是将页面解析为单词列表的缩写。不要忘了在结果中添加空格(为了清晰起见,我跳过它)

在原始版本中处理一个页面的复杂度约为50000*1000,而现在只有1000。(检查单词是否在
HashSet
中需要固定的时间)

编辑
因为我想让自己离开工作十分钟,下面是代码:)

String text=“这是一个糟糕的词,这是一个非常糟糕、可怕的词。”;
Set bankedenwords=新的HashSet(Arrays.asList(“坏”、“可怕”);
text+=“|”;//标记文本的结尾
布尔readingWord=false;
StringBuilder currentWord=新建StringBuilder();
StringBuilder结果=新建StringBuilder();
用于(int pos=0;pos
使用
java.lang.StringBuilder
-它是专门为修改的文本创建的

StringBuilder builder = new StringBuilder(page);
for (String word: wordsToDelete) {
    int position = 0;
    int newpos = 0;
    while ((newpos = builder.indexOf(word, position))>=0) {
        builder.delete(position, position+word.length());
        position = newpos;
    }
}

这只是一个想法——它不检查单词边界,问题是你有一个双for循环。这些性能通常很差,相当于x*y性能。另外,由于字符串不能在每次调用toLowerCase然后替换时更改,所以您正在创建一个新字符串。因此,您正在为列表中的每个单词创建x*y个包含整个页面的字符串。在正则表达式中使用MULTI_行和不区分大小写的选项可以避免这种情况

您可以将其简化为一个循环,并使用正则表达式一次替换所有单词

    StringBuffer buffer = new StringBuffer();
    for (String word : wordsToDelete) {
        if (buffer.length() != 0) {
            buffer.append("|");
        }
        buffer.append("(\\b");
        buffer.append(word);
        buffer.append("\\b)");
    }

    Pattern pattern = Pattern.compile(buffer.toString(), Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

    List<String> newPageList = new ArrayList<String>();

    for (String page : pages) {   
        Matcher matcher = pattern.matcher(page);
        String newPage = matcher.replaceAll("");
        newPageList.add(newPage);
    }
StringBuffer=new StringBuffer();
for(字符串字:wordsToDelete){
如果(buffer.length()!=0){
buffer.append(“|”);
}
buffer.append(“\\b”);
buffer.append(word);
buffer.append(“\\b)”);
}
Pattern=Pattern.compile(buffer.toString(),Pattern.CASE|u不区分| Pattern.MULTILINE);
List newPageList=newArrayList();
对于(字符串页:页){
Matcher Matcher=pattern.Matcher(第页);
字符串newPage=matcher.replaceAll(“”);
newPageList.add(newPage);
}

假设页面是独立的,并且如果您有多个核心,并且有很多页面要处理,那么这个循环也可以并行化:

final ArrayList<String> pages = ...;
final Set<String> wordsToDelete = ...;
final ExecutorService pageFrobber = Executors.newFixedThreadPool(8);  //pick suitable size
final List<Callable<String>> toFrobPages = new ArrayList<Callable<String>>(pages.size());

for( final String page: pages ) {
    toFrobPages.add(new Callable<String>() {
       String call() {
         return page.toLowerCase().replaceAll( "(?i)\\b" + wordToDelete + "\\b" , "" );
       }
    });
}

final List<Future<String>> frobbedPages = pageFrobber.executeAll(toFrobPages);
// the above will block until all pages are processed
// frobbedPages will contain a set of Future<String> which can be converted to strings
// by calling get()
final ArrayList pages=。。。;
最后一组字stodelete=。。。;
final Executor Service pageFrobber=Executors.newFixedThreadPool(8)//选择合适的尺寸
最终列表toFrobPages=newArrayList(pages.size());
用于(最终字符串页:页){
toFrobPages.add(新的可调用(){
字符串调用(){
返回页面.toLowerCase().replaceAll((?i)\\b“+wordToDelete+”\\b“,”);
}
});
}
最终列表frobbedPages=pageFrobber.executeAll(toFrobPages);
//在处理完所有页面之前,上述操作将被阻止
//FrobbedPage将包含一组可转换为字符串的Future
//通过调用get()

更糟糕的是,此代码无效。执行后,向量将保持不变。由于您使用的是
(?i)
,因此不需要将页面转换为小写。仅供参考:@Charlatan:我使用小写首先检查页面中是否存在单词todelete。请查看我对@Bozho.Nice的评论。但是我想有些空格和标点符号没有被考虑(或者它们是吗?@Bozho你是对的,一些技术细节被省略了(比如这个和文本解析)。虽然他们
final ArrayList<String> pages = ...;
final Set<String> wordsToDelete = ...;
final ExecutorService pageFrobber = Executors.newFixedThreadPool(8);  //pick suitable size
final List<Callable<String>> toFrobPages = new ArrayList<Callable<String>>(pages.size());

for( final String page: pages ) {
    toFrobPages.add(new Callable<String>() {
       String call() {
         return page.toLowerCase().replaceAll( "(?i)\\b" + wordToDelete + "\\b" , "" );
       }
    });
}

final List<Future<String>> frobbedPages = pageFrobber.executeAll(toFrobPages);
// the above will block until all pages are processed
// frobbedPages will contain a set of Future<String> which can be converted to strings
// by calling get()