【问题标题】:How to split a String array at every nth word?如何在每个第 n 个单词处拆分字符串数组?
【发布时间】:2020-12-12 00:02:15
【问题描述】:

我被一个(可能非常简单的)想法难住了。我正在使用 BufferedReader 读取文本文件,并在空格处拆分字符串。我需要创建一个新的字符串数组,并将前一个数组中的 3s 单词中的新元素分组,例如{The, quick, brown, fox, jumped, over, the, lazy, cat}{The quick brown, fox jumped over, the lazy cat}.

到目前为止,我提出了一个非常低效的尝试,它遍历数组并将元素和空格连接到一个新的字符串数组。它还会在新数组中留下空值,因为我每次都会增加 i+3

String line = "";
while ((line = br.readLine()) != null) {
    String words[] = line.split(" ");
    String[] result = new String[words.length - 1];

    for (int i = 0; i < words.length - 3; i += 3) {
        result[i] = words[i] + " " + words[i + 1] + " " + words[i + 2];
    }
    for (int i = 0; i < result.length; i++) {
        System.out.println(result[i]);
    }
}

输出示例:

a Goose who null null was taking a null null walk by the null null side of the null null "Good heavens!" cried null null the Goose.

【问题讨论】:

    标签: java arrays string


    【解决方案1】:

    你的朋友是:

    1. Math#ceil
    2. String#join
    3. Arrays#copyOfRange
    4. Integer#min

    演示:

    import java.util.Arrays;
    
    class Main {
        public static void main(String[] args) {
            final int SIZE = 3;
            String[] arr = { "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "cat", "Hello" };
            String[] result = new String[(int) Math.ceil((double) arr.length / SIZE)];
            for (int i = 0, j = 0; i < arr.length; i += SIZE, j++) {
                result[j] = String.join(" ", Arrays.copyOfRange(arr, i, Integer.min(arr.length, i + SIZE)));
            }
    
            System.out.println(Arrays.toString(result));
        }
    }
    

    输出:

    [The quick brown, fox jumped over, the lazy cat, Hello]
    

    工作原理

    Arrays.copyOfRange 从索引复制arr,将i 复制到索引,Integer.min(arr.length, i + SIZE) - 1 其中Integer.min(arr.length, i + SIZE) 返回arr.lengthi + SIZE 的最小值。这是i + SIZE 可能超出arr.length 导致IndexOutOfBoundsException 的最后一个副本所必需的。下面给出了arrSIZE = 310 元素的说明:

    当 i = 0 时,Arrays.copyOfRange(arr, 0, Integer.min(10, 0 + 3)) => Arrays.copyOfRange(arr, 0, 3) 会将子数组从索引 arr 返回到索引 2


    当 i = 3 时,Arrays.copyOfRange(arr, 3, Integer.min(10, 3 + 3)) => Arrays.copyOfRange(arr, 3, 6) 会将子数组从索引 arr 返回到索引 5


    当 i = 6 时,Arrays.copyOfRange(arr, 6, Integer.min(10, 6 + 3)) => Arrays.copyOfRange(arr, 6, 9) 会将子数组从索引 arr 返回到索引 8


    当 i = 9 时,Arrays.copyOfRange(arr, 9, Integer.min(10, 9 + 3)) => Arrays.copyOfRange(arr, 9, 10) 将从索引 arr 中返回子数组 9 到索引 9


    【讨论】:

    • 您好 Arvind,感谢您的回复,您提供的解决方案非常有效。我在一定程度上理解逻辑,但由于我是编程新手,我非常感谢对 Arrays.copyOfRange 方法逻辑的进一步澄清。我知道它正在返回 arr 的副本并根据最小和最终索引范围将其分配给结果数组。但我对最大索引特别困惑 - Integer.min(arr.length, i + SIZE)
    • 不客气。我为你添加了一个插图。如有任何疑问,请随时发表评论。
    【解决方案2】:

    测试这段代码:

    String line = "";
    while ((line = br.readLine()) != null) {
        String words[] = line.split(" ");
        String[] result = new String[((words.length - 1) / 3) + (((words.length - 1) % 3) > 0 ? 1 : 0)];
        int j = 0;
        for (int i = 0; i < result.length; i++) {
            result[i] = words[j] + (words.length > j + 1 ? (" " + words[j + 1]) : "") + (words.length > j + 2 ? (" " + words[j + 2]) : "");
            j += 3;
        }
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }
    }
    

    【讨论】:

    • 感谢您的示例,非常感谢。它确实有助于阐明防止越界和使用附加变量的逻辑。
    • 不客气。这不一定是最好的方法,但我认为你需要保持这种方法只是为了学习,因为你说你是 JAVA 新手,或者有更短的方法。
    • 同意!效率会随着时间的推移而提高,但我现在很高兴能够了解这类问题的逻辑。
    【解决方案3】:

    您可以使用以下方法:

    public String[] splitArray(String[] array, int splitByNumOfItems) {
        String[] newArr = new String[array.length / splitByNumOfItems];
        StringBuilder str = new StringBuilder();
        int newArrPos = 0;
        for (int i = 0; i < array.length; i++) {
            if ((i + 1) % splitByNumOfItems == 0) {
                str.append(array[i]);
                newArr[newArrPos] = str.toString();
                str.setLength(0);
                newArrPos++;
            } else {
                str.append(array[i]);
            }
        }
        return newArr;
    }
    

    测试运行

    String[] before = {
            "The", "quick", "brown",
            "fox", "jumped", "over",
            "the", "lazy", "cat"};
    
    System.out.println(Arrays.toString(splitArray(before, 3)));
    

    打印:

    [Thequickbrown, foxjumpedover, thelazycat]
    

    说明

    我们可以创建一个名为newArr 的新数组,它将容纳名为array 的原始数组的项目。

    我们可以循环遍历array的各项,每次循环,我们检查当前位置是否能被splitByNumOfItems整除。如果是,我们可以将其设置到newArr中的对应位置,由newArrPos确定。

    【讨论】:

      【解决方案4】:

      您可以iterate 在此数组的索引上使用三个元素的步骤,并在每一步使用Arrays.stream(T[],int,int) 方法获取从当前元素到下一个第三元素的元素范围,并使用joining 连接它们带空格分隔符:

      String[] arr = {
              "The", "quick", "brown",
              "fox", "jumped", "over",
              "the", "lazy", "cat"};
      
      String[] arr2 = IntStream
              // every third element 0, 3, 6
              .iterate(0, i -> i < arr.length, i -> i + 3)
              // stream over the elements of the array with
              // a range from the current element to the next
              // third element, or the end of the array
              .mapToObj(i -> Arrays.stream(arr, i, Math.min(i + 3, arr.length))
                      // join elements with whitespace delimiter
                      .collect(Collectors.joining(" ")))
              // return an array
              .toArray(String[]::new);
      
      // output line by line
      Arrays.stream(arr2).forEach(System.out::println);
      // The quick brown
      // fox jumped over
      // the lazy cat
      

      【讨论】:

        猜你喜欢
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 2012-03-17
        • 2019-11-01
        • 1970-01-01
        相关资源
        最近更新 更多