微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在一组元素中找到一个复杂元素

如何解决在一组元素中找到一个复杂元素

我有一个函数,可以让我在一组不完整的元素和至少一个元素之间找到匹配项。 22.2.X.13 一个不完整元素的示例,其中有一个项目(用X定义)可以采用任何值。

功能的目标是在一组元素中找到至少一个元素,该元素的第一个位置为22,第二个为2,第四个为13。

例如,如果我们考虑集合:

{
    20.8.31.13,32.3.29.13,24.2.12.13,19.2.37.13,22.2.22.13,27.17.22.13,26.22.32.13,22.3.22.13,20.19.12.13,17.4.37.13,31.8.34.13
} 

函数输出返回 True ,因为存在与22.2.22.13相对应的元素22.2.X.13

我的函数将每对元素(例如字符串)和元素的每一项都比较为整数:

public boolean containsElement(String element) {
    StringTokenizer strow = null,st = null;
    boolean check = true;
    String nextrow = "",next = "";
    
    for(String row : setofElements) {
        strow = new StringTokenizer(row,".");
        st = new StringTokenizer(element,".");
        
        check = true;
        while(st.hasMoretokens()) {
            next = st.nextToken();
            if(!strow.hasMoretokens()) {
                break;
            }
            nextrow = strow.nextToken();
            if(next.compareto("X") != 0) {
                int x = Integer.parseInt(next);
                int y = Integer.parseInt(nextrow);
                if(x != y) {
                    check = false;
                    break;
                }
            }
        }
        if(check) return true;
    }
    return false;

但是,这是一个昂贵的操作,尤其是当字符串的大小增加时。您能建议我另一种策略或数据结构来快速执行此操作吗?

我的解决方案与字符串紧密相关。但是,我们可以考虑其他类型的元素(例如数组,列表,树节点等)

感谢大家的回答。我已经尝试了几乎所有功能,以及试验台:

myFunction: 0ms
hasMatch: 2ms
Stream API: 5ms
isIPMatch; 2ms

我认为正则表达式的主要问题是创建模式和匹配字符串的时间。

解决方法

您要使用正则表达式,正则表达式正是针对此类任务而设计的。签出demo

22\.2\.\d+\.13

Java 8及更高版本

您可以使用Java 8或更高版本的Stream API,使用PatternMatcher类找到至少一个与正则表达式匹配的内容:

Set<String> set = ... // the set of Strings (can be any collection)

Pattern pattern = Pattern.compile("22\\.2\\.\\d+\\.13"); // compiled Pattern
boolean matches = set.stream()                           // Stream<String>
                     .map(pattern::matcher)              // Stream<Matcher>
                     .anyMatch(Matcher::matches);        // true if at least one matches

Java 7及更低版本

方法与Stream API相同:如果发现匹配项,则使用break语句进行短路的for-each循环。

boolean matches = false;
        
Pattern pattern = Pattern.compile("22\\.2\\.\\d+\\.13");
for (String str: set) {
    Matcher matcher = pattern.matcher(str);
    if (matcher.matches()) {
        matches = true;
        break;
    }
}
,

您可以按照Nikolas Charalambidis(+1)的建议,通过基于正则表达式的方式解决问题,也可以采取不同的方法。为了避免重复使用其他答案,在这里我将重点介绍使用split方法的另一种方法。

public boolean isIPMatch(String pattern[],String input[]) {
    if ((pattern == null) || (input == null) || (pattern.length <> input.length)) return false; //edge cases
    for (int index = 0; index < pattern.length; index++) {
        if ((!pattern[index].equals("X")) && (!pattern[index].equals(input[index]))) return false; //difference
    }
    return true; //everything matched
}

在通过String将项目转换为与split数组进行比较之后,您可以在循环中调用上述方法。

,

对于字符串,正则表达式可以更好地解决任务:

private boolean hasMatch(String[] haystack,String partial) {
    String patternString = partial.replace("X","[0-9]+").replace(".","\\.");
    // "22.2.X.13" becomes "22\\.2\\.[0-9]+\\.13" 
    Pattern p = Pattern.compile(patternString);
    for (String s : haystack) {
        if (p.matcher(s).matches()) return true;
    }
    return false;
}

对于其他类型的对象,这取决于它们的结构。

  • 如果有某种顺序,则可以考虑使元素实现Comparable-然后可以将它们放入TreeSet(或作为TreeMap中的键),它将始终保持排序。这样,您就只能与可以匹配的元素进行比较:mySortedSet.subSet(fromElement,toElement)仅返回这两个元素之间的元素。
  • 如果没有顺序,则只需将所有元素与“模式”进行比较。

请注意,字符串可比较的,但是它们的默认排序顺序会忽略.-分隔符的特殊语义。因此,您可以谨慎地实施基于树集的方法,以使搜索优于线性搜索。

,

其他答案已经讨论过使用正则表达式通过转换例如22.2.X.1322\.2\.\d+\.13(不要忘记也逃脱.或它们的意思是“任何”)。但是,尽管这肯定会更简单,也可能会更快一些,但它并不会降低整体复杂性。您仍然必须检查集合中的每个元素。

相反,您可以尝试以以下形式将一组IP转换为嵌套的Map

{20: {8: {31: {13: null}},19: {12: {13: null}}},22: {2: {...},3: {...}},...}

(当然,您应该只创建一次此结构,而不是为每个搜索查询创建该结构。)

然后您可以编写一个递归函数match,其大致工作原理如下(伪代码):

boolean match(ip: String,map: Map<String,Map<...>>) {
    if (ip.empty) return true // done
    first,rest = ip.splitfirst
    if (first == "X") {
        return map.values().any(submap -> match(rest,submap))
    } else {
        return first in map && match(rest,map[first])
    }
}

这应该将复杂度从O(n)降低到O(log n);越多,您越需要分支出去,但是对于X.X.X.123最多为O(n)(X.X.X.X也是微不足道的)。对于较小的集合,正则表达式可能会更快,因为它具有较少的开销,但是对于较大的集合,这应该更快。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。