使用Java流从列表中获取第n个元素

6

我有一个字符串列表,例如"/100" "/100/200"

我希望将这些字符串按照/拆分,然后得到一个整数列表的列表,如[[100],[100,200]]

我想遍历这个列表,并从每个列表中获取第n个元素(如果该列表足够长),否则转到下一个列表。

已知每个内部列表的最大长度为n

示例:

n= 3
slashString -> "/100/200/300","/200/300","/100/200/400"

在上述情况下,我想要一个整数列表,如300,400
List<Integer> output = slashString.stream()
        .map(x->Arrays.stream(x.split("/")).collect(Collectors.toList()))
        .filter(x->x.size()==3)

我能够思考到以上问题。如何最终收集整数列表中所有第三个元素。
4个回答

4

只需将每个List映射到List的第三个元素并收集:

List<Integer> list = Stream.of ("100/200/300","200/300","100/200/400")
    .map(x->Arrays.stream(x.split("/")).collect(Collectors.toList()))
    .filter(x->x.size()==3)
    .map(l->Integer.valueOf (l.get(2)))
    .collect(Collectors.toList());

请注意,您需要消除输入字符串的前导 /。否则,第1个和第3个 List 的长度将为4,并且它们不会通过筛选器。或者您可以要求 List 大小为4而不是3(并将 l.get(2) 更改为 l.get(3))。

1
更好的匹配是 int index = 3; List<Integer> result = Arrays.asList("/100/200/300", "/200/300", "/100/200/400").stream() .map(m -> Arrays.stream(m.split("/")).filter(s -> !s.isEmpty()).collect(Collectors.toList())) .filter(l -> l.size() == index) .map(l -> Integer.valueOf(l.get(index - 1))) .collect(Collectors.toList()); - Youcef LAIDANI
1
请注意 filter(s -> !s.isEmpty()),这将忽略开头的空结果,这意味着 index 应该是 3 而不是 4 - Youcef LAIDANI
1
@YCF_L 哦,我错过了那个改变。谢谢 - Eran

4

你已经接近成功了。

在过滤大小为3的列表后,获取第三个元素并将其转换为整数。

此外,请注意拆分字符串/100/200会给您一个String[]["", "100", "200"]),其中第一个元素是一个空字符串。因此,我使用skip(1)跳过了第一个元素。

List<Integer> result = slashString.stream()
            .map(x-> Arrays.stream(x.split("/"))
                    .skip(1)
                    .collect(Collectors.toList()))
            .filter(x -> x.size() >= 3)
            .map(list -> Integer.valueOf(list.get(2)))
            .collect(Collectors.toList());

4
使用正则表达式仅保留第三项,过滤掉空值,即可完成!
List<Integer> list = Stream.of("100/200/300", "200/300", "100/200/400")
    .map(s -> s.replaceAll("^([^/]/[^/]/)?([^/]+)?(/.*)?", "$2"))
    .filter(s -> !s.isEmpty())
    .map(Integer::valueOf)
    .collect(Collectors.toList());

这个正则表达式总是匹配整个字符串,并用作为第三个参数的第二组捕获来替换它,但由于所有内容都是可选的,如果没有第三组捕获结果,则第二组捕获结果为空。

这种方法只涉及到字符串处理,避免了复杂的数组代码,使事情更简单。


正则表达式很难维护。首先,你似乎忘记了第一组中的量词,因为匹配一个非/字符并不符合预期的用例。你肯定是想用[^/]*代替[^/]。第二个问题是你让第一组变成了可选项,所以对于200/300,它不会匹配第一组(不以斜杠结尾),因此后续的组将捕获第一个数字而不是为空。我更愿意使用:.replaceFirst("([^/]*+/?+){0,2}+([^/]*).*", "$2"),这不仅可以解决这些问题,还可以轻松适应支持“第n个”项目。 - Holger

3

您不需要创建中间列表。相反,将每个字符串转换为一个流,该流为空或仅包含第n个元素,使用skip(n).limit(1),并使用flatMap将所有小流合并在一起:

Pattern delimiter = Pattern.compile("/");
int n = 3;

List<Integer> result = slashString.stream()
        .flatMap(s -> delimiter.splitAsStream(s).skip(n).limit(1))
        .map(Integer::valueOf)
        .collect(toList());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接