java 处理字符串列表

0sgqnhkj  于 2023-02-28  发布在  Java
关注(0)|答案(4)|浏览(215)

我有一个字符串列表,我需要找到所有重复的,也删除所有的孩子,如果父母在列表中。我的字符串可以有一个最大4级:第0级:"根",或留空第1级:"瑞典"、"美国"等......二级:"瑞典.斯德哥尔摩"、"美国.芝加哥"等......三级:"瑞典.斯德哥尔摩. solr 纳""美国.芝加哥.西塞罗"等等......
所以如果我有一个列表["Sweden", "Sweden", "Sweden.Stockholm.Solna", "America.Chicago", "America.Chicago", "America.Chicago.Cicero"],那么只应该返回["Sweden", "America.Chicago"]
如何使用Java,最好是java 8流API来实现这一点?
以下两种方法可用于检查一个字符串是另一个字符串的父级还是子级:

private boolean isChildOf(String parentPath, String path) {
   return path.startsWith(parentPath.isBlank() ? parentPath : parentPath + ".") && !path.equals(parentPath);
}
private boolean isParentOf(String childPath, String path) {
   return childPath.startsWith(path + ".") && !path.equals(childPath);
}
axkjgtzd

axkjgtzd1#

下面是我的实现,我已经测试过了,并且工作正常。

//initialize list from example
List<String> nodes = Arrays.asList(new String[] {"Sweden", "Sweden", "Sweden.Stockholm.Solna", "America.Chicago", "America.Chicago", "America.Chicago.Cicero"});
//sort into map grouped by the root level of the entries (regardless of if the "root" exists in list or not)
Map<String, List<String>> groups = nodes.stream().collect(Collectors.groupingBy(s -> isRoot(s) ? s : s.substring(0, s.indexOf(".")), Collectors.toList()));
//since they are already sorted by the root, we can just return the shortest string in each list
List<String> parents = groups.entrySet().stream().map(e -> getParent(e.getValue())).collect(Collectors.toList());
System.out.println(parents);

下面是我使用的自定义方法

//return the shortest String in the list
private String getParent(List<String> nodes) {
    return nodes.stream().min(Comparator.comparingInt(s -> s.length())).get();
}

private boolean isRoot(String s) {
    return !s.contains(".");
}

编辑:由于OP已经接受了答案,我将离开之前的实现。然而,正如在评论中指出的,这个解决方案错过了一些父元素共享相同根级别的情况。我已经修改了我的实现以适应这种情况。对于List<String> nodesMap<String, List<String>> groups没有必要进行任何更改,所以我将只发布修改后的List<String> parents和新的helper方法。

List<String> parents = groups.entrySet().stream().distinct().map(e -> {
        List<String> set = e.getValue();
        int min = set.stream().mapToInt(s -> numLevels(s)).min().getAsInt();
        return set.stream().distinct().filter(s -> numLevels(s) == min).toList();
    }).flatMap(List::stream).collect(Collectors.toList());

数值水平法

private static int numLevels(String s) {
    return (int)s.chars().filter(i -> i == (int)'.').count();
}

新的实现使用distinct来删除重复项,然后为groupsMap中的每个列表条目确定最小级别数(使用.的出现次数),并返回符合条件的元素的过滤列表,最后将结果扁平化为单个列表。

juzqafwq

juzqafwq2#

如果isChildOf方法是正确的,那么使用嵌套循环对照列表中的每个其他元素(当前元素除外)检查每个元素就可以解决这个问题。
首先删除重复项

Set<String> set = new HashSet<>(list);
list.clear();
list.addAll(set);

然后删除子项

for(string child : list) {
    for(string parent : list) {
       if (isChildOf(Parent, Child)):
          list.remove(Child)
    }
}
dwbf0jvd

dwbf0jvd3#

创建新列表以获取所有重复项

Set<String> set = new HashSet<String>();
List<String> duplicates = new ArrayList<String>();
list.forEach(word -> {
            
    if(!set.add(word))
        duplicates.add(word);

});

创建另一个列表以获取所有查尔兹

List<String> childs = new ArrayList<String>();
for(String child : duplicates) {
    for(String parent : duplicates) {
       if (isChildOf(parent, child))
           childs.add(child);
    }
}

从重复项中删除所有查尔兹项

duplicates.removeAll(childs);

Final duplicates是您想要的最终结果。

dwbf0jvd

dwbf0jvd4#

这里有一种使用集合的方法,它适用于层次结构的任何深度。

  • 首先将列表添加到集合中。这将删除不需要的重复项。
  • 然后遍历该集合的副本并删除每个元素
  • 如果当前元素不等于测试中的元素
  • 并且当前元素从测试中的元素开始。
List<String> hierarchy = List.of(
       "Sweden.Stockholm.Solna", "America.Chicago", "America.Chicago",
       "America.Chicago.Cicero", "Sweden.Stockholm.Solna","Sweden", "Sweden");

Set<String> set = nodes.stream()
        .collect(Collectors.toCollection(HashSet::new));

for (String str : new HashSet<>(set)) {
    set.removeIf(v -> !v.equals(str) && v.startsWith(str));
}

set.forEach(System.out::println);

印刷品

Sweden
America.Chicago

相关问题