我有 2 個串列,
是一個名為 tablerows 的字串串列。
是一個物件串列,每個物件都包含一個字串值串列(除其他外)
我正在嘗試通過流迭代它們,如下所示:
tableRows.forEach(row -> objects.forEach(o -> o.getValues().forEach(v -> {
任務是找到所有值“v”以及它們在哪個 tablerow 中使用(如果它們是),然后呼叫一個方法來處理 tablerow、其中使用的值以及它所屬的物件名稱.
if (doesContain(row.getText(), v.getValue())) {
methodCall....
}
目前已通過正則運算式模式驗證
doesContain(String string, String substring) {
String pattern = "^" substring " \\b|\\b " substring " \\b|\\b " substring "$";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(string);
return m.find();
}
代碼有效,然而,thirst List 包含 3000-6000 個字串(將來還會有更多),而第二個串列有大約 100 個物件,每個物件的串列中有大約 20 個字串來檢查......
目前,完成 3000 個字串的串列大約需要 1.3 分鐘,而在 1 分鐘后會呼叫超時。
主要瓶頸似乎是由于使用了 Pattern 和 Matcher,大約需要 40 秒。使用詞邊界是必要的,所以我不能使用等于、包含或類似的方法。我的想法是以某種方式直接在流中使用謂詞,到目前為止沒有成功。
是否可以直接在流中使用正則運算式,同時保留相互連接的“行”和“v”值,然后為每個成功對呼叫方法?
或者有沒有可能更快的替代方法?
編輯:例如:主要:
public class main {
public static void main(String[] args) {
ArrayList<String> tableRows = new ArrayList<>();
tableRows.add("Text one");
tableRows.add("Text two");
tableRows.add("Text three");
tableRows.add("Text four");
tableRows.add("Text five");
ArrayList<String> valueList = new ArrayList<>();
valueList.add("one");
valueList.add("two");
valueList.add("none");
valueList.add("four");
valueList.add("abc");
ArrayList<testObject> objects = new ArrayList<testObject>();
objects.add(new testObject("thirstName", valueList));
objects.add(new testObject("secondName", valueList));
String replacePattern = Pattern.quote(".") "|" Pattern.quote("?") "|" Pattern.quote("!") "|"
Pattern.quote(",") "|" Pattern.quote(";");
tableRows.forEach(row -> objects.forEach(o -> o.getValues().forEach(v -> {
if (doesContain(row, v,replacePattern)) {
System.out.println("Value :" v " of Object " o.getName() " is used in row: " row);
}
})));
}
private static boolean doesContain(String string, String substring,String replacePattern) {
string = string.toLowerCase().replaceAll(replacePattern, "");
substring = substring.toLowerCase();
String pattern = "^" substring " \\b|\\b " substring " \\b|\\b " substring "$";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(string);
return m.find();
}
}
測驗物件類:
public class testObject {
private String name;
private ArrayList<String> values;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<String> getValues() {
return values;
}
public void setValues(ArrayList<String> values) {
this.values = values;
}
public testObject() {
this.name = "testName";
this.values = (ArrayList<String>) List.of("one","two");
}
public testObject(String name, ArrayList<String> values) {
this.name = name;
this.values = values;
}
}
示例輸出:
Value: one of Object: thirstName is used in row: Text one
Value: one of Object: secondName is used in row: Text one
Value: two of Object: thirstName is used in row: Text two
Value: two of Object: secondName is used in row: Text two
Value: four of Object: thirstName is used in row: Text four
Value: four of Object: secondName is used in row: Text four
uj5u.com熱心網友回復:
當您想確保匹配是一個完整的單詞時,您應該簡單地將單詞邊界錨添加到單詞,而不是添加空格并嘗試將錨應用于前一個和下一個單詞。這簡化了模式匹配word,但不words至"\\bword\\b"。此外,您可以將串列中的所有單詞組合到一個模式中,例如"\\b(one|two|none|four|abc)\\b"搜索這些單詞中的任何一個的第一次出現。這消除了迭代單詞的需要。但如果字串中出現多個這些詞,它可能會報告不同的詞。
當您將迭代邏輯更改為時,objects.forEach(o -> tableRows.forEach(row -> …))您只需要為每一行構造每個模式一次而不是重復。但這當然會以不同的順序列印結果。
然后,避免將所有字串轉換為大寫或小寫的普遍反模式,以有效執行不區分大小寫的搜索。Java 有專門的不區分大小寫搜索的方法,我不知道為什么這么多開發人員忽略它們而寧愿執行昂貴的轉換。請注意,搜索可以在第一次出現時停止,而toLowercase()轉換必須在搜索開始之前處理整個字串,可能會產生一個新字串。
將這些點放在一起,您可以執行以下操作:
objects.forEach(o -> {
Pattern p = Pattern.compile(
o.getValues().stream().collect(Collectors.joining("|", "\\b(", ")\\b")),
Pattern.CASE_INSENSITIVE);
tableRows.forEach(row -> {
Matcher m = p.matcher(row);
if(m.find()) {
System.out.println("Value: " m.group()
" of Object " o.getName() " is used in row: " row);
}
});
});
這是從getValues()每個testObject實體回傳的串列中構造組合模式。由于模式可能匹配這些單詞中的任何一個,我們必須查詢匹配器 ( m.group()) 以找出我們找到的單詞。請注意,可能會發生更多事件。此匹配操作在字串中找到的第一個單詞處停止,而您的原始代碼在已找到的串列的第一個單詞處停止,即使它在字串中出現的時間比在串列中出現的另一個詞晚。
如果您多次執行此操作,您甚至可以將模式存盤在其testObject自身中,例如
public class TestObject {
private String name;
private List<String> values;
private Pattern pattern;
public TestObject() {
this("testName", List.of("one","two"));
}
public TestObject(String name, List<String> values) {
this.name = name;
setValues(values);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = List.copyOf(values);
pattern = Pattern.compile(
this.values.stream().collect(Collectors.joining("|", "\\b(", ")\\b")),
Pattern.CASE_INSENSITIVE);
}
public Pattern getPattern() {
return pattern;
}
}
I took the opportunity to fix some other issues of this class, like not assuming that every List is an ArrayList. It also always uses an immutable list for its internal storage, to ensure that no-one can change it without a corresponding Pattern update.
Besides keeping the patterns between different match operations, this also allows to check the objects in the same order as your original code, e.g.
tableRows.forEach(row -> objects.forEach(o -> {
Matcher m = o.getPattern().matcher(row);
if(m.find()) {
System.out.println("Value: " m.group()
" of Object " o.getName() " is used in row: " row);
}
}));
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/314070.html
上一篇:優化MongoDB聚合查詢性能
