【问题标题】:How to get Item from set based on parameter using Java8 features如何使用 Java8 功能根据参数从集合中获取项目
【发布时间】:2018-06-05 03:38:18
【问题描述】:

我有一套以下物品

Set<String> formatLookup = new HashSet<>();
formatLookup.add("DHMdhm");
formatLookup.add("THMthm");
formatLookup.add("JHMjhm");

我正在传递一个字符串,如下所示

String filterVal = "THM";

现在我想检查过滤器值存在于集合的哪个索引中(过滤器值顺序可能会有所不同,如 THM、HTM、MHT 等),并且我想从集合中返回该项目。下面是这个的代码,它正在工作。

private static String getStoredFilter(String filterVal) {
    String format = "DHMdhm";
    boolean found = false;
    Set<String> formatLookup = new HashSet<>();
    formatLookup.add("DHMdhm");
    formatLookup.add("THMthm");
    formatLookup.add("JHMjhm");
    Iterator<String> setIterator = formatLookup.iterator();
    while (setIterator.hasNext()) {
        String fmt = setIterator.next();
        for (int j = 0; j < filterVal.length(); j++) {
            if (!(fmt).contains(String.valueOf(filterVal.charAt(j)))) {
                found = false;
                break;
            } else {
            found = true;
            }
        }
        if (found) {
            return fmt;
        }
    }
    return null;
}

我想使用 Java8 功能。我是 Java8 的新手,我尝试使用流和 foreach。但是,由于foreach 无法返回值,所以我不确定如何完成。

你能帮我解决这个问题吗?

【问题讨论】:

  • Set 的索引...

标签: java lambda foreach java-8 java-stream


【解决方案1】:

您可以通过简单地将键和输入都带入规范排列来处理排列,例如只需对它们进行排序:

static String canonical(String s) {
    char[] c = s.toCharArray();
    Arrays.sort(c);
    return String.valueOf(c);
}

准备一个从规范键到指定字符串的映射

// do this only once
private static final Map<String,String> formatLookup
    = Stream.of("DHMdhm", "THMthm", "JHMjhm")
            .collect(Collectors.toMap(s -> canonical(s), Function.identity()));

和实际操作

private static String getStoredFilter(String filterVal) {
    String key = canonical(filterVal);

    // check whether there's an exact match
    String quickChecked = formatLookup.get(key);
    if(quickChecked!=null) return quickChecked;

    // search for substring matches
    return formatLookup.entrySet().stream()
        .filter(e -> e.getKey().contains(key))
        .map(Map.Entry::getValue)
        .findAny().orElse(null);
}

如果字符串可能包含重复字符并且您想处理它,您只需更改 canonical 方法,例如

static String canonical(String s) {
    return s.codePoints().collect(BitSet::new, BitSet::set, BitSet::or).stream()
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}

【讨论】:

  • 感谢@Holger,它按预期工作。但我想知道它是否会导致性能问题,而不是我提到的代码。
  • 这总是比探测所有可能的排列要快,尤其是对于较长的字符串,因为可能的排列数量会激增。
  • 它接受重复字符也像THHHM,它不应该接受它。
  • 这就是为什么我提供了canonical 的两个变体,所以你可以使用任何符合你关于重复的政策的东西。
【解决方案2】:

获得匹配的第一个元素

    String e = formatLookup.stream().filter(s -> s.startsWith(filterVal)).findFirst().get();

收集所有匹配的

    List<String> elems = formatLookup.stream().filter(s -> s.startsWith(filterVal)).collect(Collectors.toList());

使用 Java9 获取第一个匹配元素的位置(而不是 Set 使用 List 用于基于索引)

    long index = formatLookup.stream().dropWhile(s -> s.startsWith(filterVal)).count();

【讨论】:

  • @Sarvana 这是返回 DHMdhm 而不是 THMthm?
【解决方案3】:

如果您想使用 Stream API,您可以使用 filter 方法来删​​除您不想要的值,然后使用 findAny() 方法来获取与过滤谓词匹配的项目。

如果没有项目匹配filter 谓词findAny() 将返回一个空可选

private static String getStoredFilter(String filterVal) {
    Set<String> formatLookup = new HashSet<>();
    formatLookup.add( "DHMdhm");
    formatLookup.add( "THMthm");
    formatLookup.add( "JHMjhm");

    Optional<String> matchedVal = formatLookup.stream()
            .filter(val -> val.contains(filterVal))
            // At this point only matched values will be available
            .findAny(); // Get the first one that matches

    // Return the matched value if there is any, otherwise returns null
    return matchedVal.orElse(null);
}

【讨论】:

    【解决方案4】:

    这是可以做到的:

    Set<String> formatLookup = new HashSet<>();
    formatLookup.add("DHMdhm");
    formatLookup.add("THMthm");
    formatLookup.add("JHMjhm");
    String filterVal = "THM";
    
    String string = formatLookup.stream()
        .filter(s -> s.contains(filterVal))
        .findFirst()
        .orElse("noElement");
    System.out.println(string);
    

    您的输出将是:THMthm

    如果要初始化集的索引,请使用以下代码:

    Set<String> formatLookup = new HashSet<>();
    formatLookup.add("DHMdhm");
    formatLookup.add("THMthm");
    formatLookup.add("JHMjhm");
    String filterVal = "THM";
    List<String> list = new ArrayList<String>(formatLookup);
    
    String string = formatLookup.stream()
        .filter(s -> s.contains(filterVal))
        .findFirst()
        .orElse("noElement");
    System.out.println(list.indexOf(string));
    

    您的输出将是:1

    如果您想使用 filterVal 字符串的所有组合,请使用以下方法:

    private static void permutation(String prefix, String s) {
        int n = s.length();
        if (n == 0) {
            System.out.println(prefix);
        } else {
            for (int i = 0; i < n; i++)
                permutation(prefix + s.charAt(i), s.substring(0, i) + s.substring(i + 1, n));
        }
    }
    

    这样调用这个方法的输出:permutation("", filterVal);是:

    THM
    TMH
    HTM
    HMT
    MTH
    MHT
    

    【讨论】:

    • 您可能想改用findAny 而不要直接调用get。如果不存在这样的值会怎样?
    • 谢谢@Alex。但是一个问题,如果过滤器值的顺序不同,如 THM、HTM、MHT 等,怎么办?
    • 不客气!没关系,因为我们使用的是findFirst()。它从您的 Set 中找到第一个匹配项。使用更新的答案,如果没有发生,则不会抛出异常。
    • @Eugene 刚刚更新了我的答案。感谢您的评论。
    • @Alex 如果 filterValue 的顺序发生变化,是否可以获得值?我想要如果过滤器值的所有字符都存在于集合的任何项目中,然后返回该项目。
    猜你喜欢
    • 2021-03-06
    • 1970-01-01
    • 2013-09-24
    • 2020-02-05
    • 2020-04-30
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多