【问题标题】:How to group by array index如何按数组索引分组
【发布时间】:2021-02-21 18:05:05
【问题描述】:

我正在尝试按其索引除以 4 对元素数组进行分组。例如,在以下输入中,由于 int_arr 的索引除以 4 返回 0、0、0、0、1、1、1 , 1, 2, 2, 2, 2, 我希望将它们分组在str_arr中的元素下,其中A对应int_arr中的元素1, 2, 3, 4等等。

我知道我需要将int_arr 中的元素转换为字符串,并且我还需要一个映射来保存所有元素,以便str_arr 中的元素是键和连接的元素int_arr 中的值。但是,我很难根据元素的索引除以 4 来对元素 int_arr 进行分组,我需要对此有所了解。

输入:

int[] int_arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12};
String[] str_arr = {A, B, C, D};

想要的输出:

{A= 1, 2, 3, 4, B = 5, 6, 7, 8, C = 9, 19, 11, 12}

【问题讨论】:

  • 请包含您目前拥有的代码。

标签: java arrays hashmap


【解决方案1】:

我想您可以将一维整数数组拆分为二维对象数组,其中该二维数组的每个 row 的第一个元素包含一个自动生成的大写字母前缀字符串(从字母 A),其余的 row 元素包含拆分整数数组中的整数值。换句话说,如果你有一个由 12 个整数元素组成的整数 (int[]) 数组:

int[] int_arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

并且您想将此数组顺序地分成 4 段,那么您最终会得到一个由 3 行组成的二维对象数组 (Object[][])每行包含 5 列。永远记住,第一列是可选地为前缀字符串保留的:

[ [A, 1, 2, 3, 4], 
  [B, 5, 6, 7, 8], 
  [C, 9, 10, 11, 12] ]

但是如果提供的 int[] 数组包含 14 个整数元素并且不能被 4 等分怎么办?然后在仅包含 3 列的 2D 数组中创建第 4 行,例如:

[ [A, 1, 2, 3, 4], 
  [B, 5, 6, 7, 8], 
  [C, 9, 10, 11, 12],
  [D, 13, 14] ]

但是,如果 int[] 数组中有超过 26 个整数元素,比如说 121 或更多整数元素怎么办?一旦前缀自动生成器通过了字母Z,每一行的前缀字符串是什么?前缀自动生成器然后生成前缀字符串:

AA, AB, AC, ..., AZ, 
BA, BB, BC, ..., BZ,
...................,
ZA, ZB, ZC, ..., ZZ,
AAA, AAB, AAC, ..., AAZ,
and so on, and so on...

以下名为 splitIntArrayTo2DArrayWithLetterPrefix() 的 Java 方法将执行此操作。是的......我知道这是一个疯狂的长名字,但它是针对这个特定目的的描述性的。您可以随时将其更改为您喜欢的任何内容:

/**
 * Creates a two dimensional Object array (Object[][]) from a supplied
 * single dimensional integer array (int[]) based on the supplied desired
 * number of columns for each row of the created 2D Array. The first element
 * of every row within the newly created 2D array will be a string letter
 * prefix starting from the letter 'A'. So if we have an integer array which
 * consists of:
 * <pre>
 *
 *    int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};</pre><br>
 * <p>
 * and we want to split this single dimensional array into a 2D array with
 * each row consisting of 3 columns which will actually be 4 columns because
 * the column index 0 of each row is reserved for an auto generated prefix
 * string. When this above int[] array is run through this method the return
 * 2D Object[] array will consist of:
 * <pre>
 *
 *     [A, 1, 2, 3]
 *     [B, 4, 5, 6]
 *     [C, 7, 8, 9]
 *     [D, 10, 11, 12]</pre><br>
 * <p>
 * If the single dimensional int[] array is large enough whereas the rows
 * span greater than to handle the prefix string of A to Z then the prefix
 * string automatically changes to AA to ZZ, then to AAA to ZZZ, then to
 * AAAA to ZZZZ, and so on. When the rows get to a 4 letter prefix string
 * then we're talking about several thousands of Array elements.
 *
 * @param int_arr         (Single Dimensional int[] Array) The integer array
 *                        to split.<br><br>
 *
 * @param desiredColumns  (Integer - int) The desired number of columns to
 *                        be contained within the created 2D array for each
 *                        array row. If during processing the final elements
 *                        of the int[] array does not mean the desired
 *                        columns requirement then the last row of the
 *                        returned 2D Object[][] array will contain those
 *                        elements, for example, if the supplied int[] array
 *                        contained 13 elements<pre>
 *
 *    int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};</pre><br>
 *
 * and we want to split this array into a 2D array with each row consisting
 * of 3 columns then our returned 2D Object[] array will consist of:
 * <pre>
 *
 *     [A, 1, 2, 3]
 *     [B, 4, 5, 6]
 *     [C, 7, 8, 9]
 *     [D, 10, 11, 12]
 *     [E, 13]</pre><br>
 *
 * Notice the last row, it only consists of 2 elements instead of 4 (the
 * prefix string and the final int[] array element). No array element is
 * ignored within the supplied int[] array. All elements are placed into the
 * 2D Object[][] array even if the column count for the last row is
 * short.<br>
 *
 * @param dontApplyPrefix (Optional - Boolean) Default is false. By default
 *                        the first element in each 2D array row (at index
 *                        0) is reserved for a auto-generated letter prefix
 *                        string. If true is supplied then no letter prefix
 *                        string is applied to the returned 2D Object[][]
 *                        Array, the int[] array is merely split into 
 *                        individual columnar rows as specified by the 
 *                        desiredColumns parameter argument. Nothing, true, 
 *                        false, or null can be supplied to this optional 
 *                        parameter.
 *
 * @return (Two Dimensional Object[][] Array) The created 2D Object Array.
 */
public static Object[][] splitIntArrayTo2DArrayWithLetterPrefix(int[] int_arr,
                int desiredColumns, Boolean... dontApplyPrefix) {
    boolean noPrefix = false;
    if (dontApplyPrefix != null && dontApplyPrefix.length > 0) {
        noPrefix = dontApplyPrefix[0];
    }
    if (int_arr.length == 0 || (desiredColumns < 1 && desiredColumns > int_arr.length)) {
        return null;
    }
    int availableRows = int_arr.length % desiredColumns == 0
            ? (int_arr.length / desiredColumns)
            : int_arr.length / desiredColumns + 1;

    Object[][] newArray = new Object[availableRows][];
    Object[] innerArray = new Object[!noPrefix ? desiredColumns + 1 : desiredColumns];
    String rowPrefix = "";
    int columnCount = 0;
    int rowCount = 0;
    for (int i = 0; i < int_arr.length; i++) {
        if (columnCount == 0 && !noPrefix) {
            /* Generate a row prefix letter string for the first column of row.
               The prefix letter will always start with 'A' and increment up
               the alphabet for each new array row until 'Z' is reached at which
               point the prefix changes to 'AA', then 'AB' for the next row and
               so on until the the array creation has completed.            */
            int val = rowCount;
            StringBuilder sb = new StringBuilder(String.valueOf((char) ('A' + (val % 26))));
            while ((val = (val / 26 - 1)) >= 0) {
                sb.append((char) ('A' + (val % 26)));
            }
            rowPrefix = sb.reverse().toString();
            innerArray[columnCount] = rowPrefix;
            columnCount++;
        }
        innerArray[columnCount] = int_arr[i];
        columnCount++;
        if (!noPrefix ? columnCount > desiredColumns : columnCount == desiredColumns) {
            newArray[rowCount] = innerArray;
            innerArray = new Object[noPrefix && int_arr.length - (i + 1) < desiredColumns ? int_arr.length - (i + 1) : noPrefix ? desiredColumns : int_arr.length - (i + 1) < desiredColumns ? int_arr.length - i : desiredColumns + 1];
            columnCount = 0;
            rowCount++;
        }
    }
    if (innerArray.length > 0 && innerArray[0] != null) {
        newArray[rowCount] = innerArray;
    }
    return newArray;
}

如何使用(或测试)上述方法:

生成一个 int[] 数组进行测试:

int numberOfElements = 12; // Change to whatever size you want.
int[] int_arr = new int[numberOfElements]; //{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
for (int i = 0; i < int_arr.length; i++) {
    int_arr[i] = i + 1;
}

调用方法:

// The number elements in a group to split the int_arr[] array into.
int desiredNumberOfColumns = 4; 
boolean dontUseAutoPrefix = false;  // Default
Object[][] myArray = splitIntArrayTo2DArrayWithLetterPrefix(int_arr, 
                           desiredNumberOfColumns, dontUseAutoPrefix);

显示返回的数组:

System.out.println("Rows of the 2D Array created:");
for (int i = 0; i < myArray.length; i++) {
    System.out.println((i + 1) + ") " + Arrays.toString(myArray[i]));
}
System.out.println();
System.out.println("Size of the Array is " + myArray.length
        + " literal rows consisting of " + myArray[0].length
        + " columns in each row");
System.out.print("where the first column holds a prefix "
        + "string and the other " + (myArray[0].length - 1)
        + " columns hold" + System.lineSeparator()
        + "integer values derived from the supplied int[] array.");
int lastRowColumnCount = myArray[myArray.length - 1].length;
System.out.println(lastRowColumnCount < desiredNumberOfColumns + 1
        ? " Keep in mind however" + System.lineSeparator()
        + "that the last array row consists of only "
        + lastRowColumnCount + " columns, one of which is the "
        + System.lineSeparator() + "prefix string. " : "");

输出:

Rows of the 2D Array created:
1) [A, 1, 2, 3, 4]
2) [B, 5, 6, 7, 8]
3) [C, 9, 10, 11, 12]

Size of the Array is 3 literal rows consisting of 5 columns in each row
where the first column holds a prefix string and the other 4 columns hold
integer values derived from the supplied int[] array.

以您喜欢的方式显示返回的数组

System.out.println("Desired display as per Original Post:");
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < myArray.length; i++) {
    String elementalString = Arrays.toString(myArray[i]);
    elementalString = elementalString.substring(elementalString.indexOf(",") + 1,
            elementalString.lastIndexOf("]")).trim();
    if (!sb.toString().isEmpty()) { 
        sb.append(", "); 
    }
    sb.append(myArray[i][0].toString()).append(dontUseAutoPrefix ? ", " : " = ")
              .append(elementalString);
}
System.out.println(sb.toString());

输出:

Desired display as per Original Post:
A = 1, 2, 3, 4, B = 5, 6, 7, 8, C = 9, 10, 11, 12

【讨论】:

    【解决方案2】:

    如果我正确理解了你的问题,你需要这样的东西:

    int outputLength = (int)Math.ceil((double)int_arr.length / 4);
    String[] output = new String[outputLength];
    
    int i = 0;
    int integerPart = 0;
    
    for(String label: str_arr) {
        if(i >= int_arr.length) break;
            
        StringBuilder group = new StringBuilder();
        group.append(label + "= ");
    
        while(i < int_arr.length && i / 4 == integerPart) {
            group.append(int_arr[i]);
            ++i;
            
            if(i / 4 == integerPart) {
                group.append(", ");
            }
        }
        
        output[integerPart] = group.toString();
        integerPart++;
    }
    

    【讨论】:

      【解决方案3】:

      所需的输出类似于映射,其键取自 str_arr,值 - 子数组或子列表取自 int_arr。为此目的使用 Stream API 可能会很方便:

      Map<String, int[]> result = IntStream.range(0, (int)Math.ceil(int_arr.length / 4.0))
                   .boxed()
                   .collect(Collectors.toMap(
                       i -> str_arr[i],
                       i -> Arrays.copyOfRange(int_arr, i * 4, Math.min(i * 4 + 4, int_arr.length))
                   ));
      
      result.forEach((k, v) ->  System.out.printf("%s -> %s%n", k, Arrays.toString(v)));
      

      输出:

      A -> [1, 2, 3, 4]
      B -> [5, 6, 7, 8]
      C -> [9, 10, 11, 12]
      

      要获取列表,可以使用另一个流和Collectors::toList 来代替Arrays::copyOfRange

      Map<String, List<Integer>> mapOfLists = IntStream.range(0, (int)Math.ceil(int_arr.length / 4.0))
                   .boxed()
                   .collect(Collectors.toMap(
                       i -> str_arr[i],
                       i -> IntStream.range(i * 4, Math.min(i * 4 + 4, int_arr.length))
                          .mapToObj(j -> int_arr[j])
                          .collect(Collectors.toList())
                   ));
      System.out.println(mapOfLists);
      

      输出:

      {A=[1, 2, 3, 4], B=[5, 6, 7, 8], C=[9, 10, 11, 12]}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-07
        • 1970-01-01
        • 2018-01-08
        • 2014-06-10
        • 2020-06-10
        • 2020-11-20
        相关资源
        最近更新 更多