简体   繁体   English

将2D锯齿状数组转换为适当的Java数组

[英]Convert 2D jagged array to proper array Java

I am trying to solve the following problem: I have a 2D jagged array 我正在尝试解决以下问题:我有一个2D锯齿状阵列

[[1, 2], [1], [3, 4], [2, 3, 4]]

which I would like to convert to a normal 2D array. 我想将其转换为普通的2D数组。 Currently, I managed to get this one 目前,我设法得到了这个

[[1, 2, 0, 0], [1, 0, 0, 0], [3, 4, 0, 0], [2, 3, 4, 0]]

but that is not what I want. 但这不是我想要的。 Goal is to have a normal array indices equaling the original jagged one. 目标是使普通数组索引等于原始锯齿形索引。 In other words, I would like to match the value from the original jagged array to the index starting from 1 in the new proper array. 换句话说,我想将原始锯齿状数组中的值与新的适当数组中从1开始的索引进行匹配。 Here is my desired output 这是我想要的输出

[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]]

Here is my code which produces this array, which is not quite what I would like to have: 这是我的代码,它产生这个数组,而这并不是我想要的:

[[1, 2, 0, 0], [1, 0, 0, 0], [3, 4, 0, 0], [2, 3, 4, 0]]
import java.util.*;

public class MultiDarrays {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("Get number of two parameters: cyclists and bicycles: ");

        int c = sc.nextInt();
        int b = sc.nextInt();

        System.out.println("cyclists: " + c + " " + "bicycles: " + b);

        ArrayList<ArrayList<Integer>> multilist = new ArrayList<ArrayList<Integer>>();
        for (int i = 0; i < c; i++) {

            List<Integer> integers = new ArrayList<Integer>();
            int num = sc.nextInt();
            for (int j = 0; j < num; j++) {

                int elem = sc.nextInt();
                integers.add(elem);
            }
            multilist.add((ArrayList<Integer>) integers);
        }

        for (int i = 0; i < multilist.size(); i++) {
            System.out.println("Elements are: " + multilist.get(i));
        }
        sc.close();

        int[][] array = new int[multilist.size()][b];
        for (int i = 0; i < array.length; i++) {
            array[i] = new int[multilist.get(i).size()];
        }
        for (int i = 0; i < multilist.size(); i++) {
            for (int j = 0; j < multilist.get(i).size(); j++) {
                array[i][j] = multilist.get(i).get(j);
            }
        }

        System.out.println(Arrays.deepToString(array));

        int[][] full_array = new int[c][b];
        System.out.println(Arrays.deepToString(full_array));

        // copy elements from jagged to normal 2D array
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                full_array[i][j] = array[i][j];
            }
        }

        System.out.println(Arrays.deepToString(full_array));
    }
}


Output: 输出:

Get number of two parameters: cyclists and bicycles: 
4 4
cyclists: 4 bicycles: 4
2 1 2
1 1
2 3 4
3 2 3 4
Elements are: [1, 2]
Elements are: [1]
Elements are: [3, 4]
Elements are: [2, 3, 4]
[[1, 2], [1], [3, 4], [2, 3, 4]]
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[1, 2, 0, 0], [1, 0, 0, 0], [3, 4, 0, 0], [2, 3, 4, 0]]

When you want to write the values to the correct indices they represent, then you can't just do full_array[i][j] = array[i][j] , because this ignores the value and just simply "fills" the array, because j just increments normally. 当您想将值写入它们所代表的正确索引时,则不能只执行full_array[i][j] = array[i][j] ,因为这会忽略该值而只是“填充”数组,因为j只是正常增加。
What you actually need to do is use the value of array[i][j] as index specification: 您实际需要做的是使用array[i][j]作为索引规范:

full_array[i][array[i][j] - 1] = array[i][j];

Mind that you need to reduce 1, because your values start from "1", but array indices from "0". 请注意,您需要减少1,因为您的值从“ 1”开始,而数组索引从“ 0”开始。

Now the output is like you expect it to be: 现在输出就像您期望的那样:

[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]] [[1、2、0、0],[1、0、0、0],[0、0、3、4],[0、2、3、4]]


Now to some minor code improvements. 现在进行一些小的代码改进。

  1. ArrayList<ArrayList<Integer>> multilist = new ArrayList<ArrayList<Integer>>(); should be refactored to List<List<Integer>> multilist = new ArrayList<>(); 应该重构为List<List<Integer>> multilist = new ArrayList<>(); , because should declare your types as open as they could be, but as narrow as they need to be. ,因为应将您的类型声明为尽可能开放 ,但应根据需要声明为狭窄 You need a List, but you actually don't care it they are an ArrayList or for example a LinkedList. 您需要一个列表,但实际上并不关心它们是ArrayList还是例如LinkedList。 Also read Java - declaring from Interface type instead of Class . 另请阅读从接口类型而不是类声明Java

  2. This cast multilist.add((ArrayList<Integer>) integers) is not needed. multilist.add((ArrayList<Integer>) integers)multilist.add((ArrayList<Integer>) integers) You had to added because you (correctly) declared integers as List<Integer> instead of ArrayList<Integer> , but since we fixed that in "1." 您必须添加,因为(正确)将integers声明为List<Integer>而不是ArrayList<Integer> ,但是由于我们将其固定为“ 1”。 you don't need it anymore. 您不再需要它。

  3.  for (int i = 0; i < multilist.size(); i++) { System.out.println("Elements are: " + multilist.get(i)); } 

    can be replace with an enhanced-for-loop: 可以替换为增强型循环:

     for (List<Integer> integers : multilist) { System.out.println("Elements are: " + integers); } 

There are several general issues with the code in the current form. 当前表单中的代码存在一些一般性问题。

It's annoying to test it, because you always have to enter the input values. 测试它很烦人,因为您总是必须输入输入值。 Define them once, so that you can quickly and easily test your code. 一次定义它们,以便您可以快速轻松地测试代码。

The use of List is not really necessary. 使用List并不是必须的。 When your input and output really are int[] arrays, you can implement your conversions based on those. 当您的输入和输出实际上是int[]数组时,您可以基于这些数组实现转换。 Although in many cases, List has advantages, in doubt you could add conversion methods between int[] and List<Integer> and between int[][] and List<List<Integer>> . 尽管在很多情况下List都有优势,但是毫无疑问,您可以在int[]List<Integer>之间以及int[][]List<List<Integer>>之间添加转换方法。

In general, when you have a task with a multidimensional data structure like an int[][] or a List<List<Integer>> , and you want to perform an operation on the inner elements, it is beneficial to create a dedicated method for that. 通常,当您具有带有int[][]List<List<Integer>>类的多维数据结构的任务,并且想要对内部元素执行操作时,创建专用方法会非常有益。为了那个原因。 As a simplified example: When you have a method like 举一个简化的例子:当您有一个类似

static void addToEachElement2D(int array[][], int valueToAdd) { ... }

then this method could/should be implemented based on a method 那么这个方法可以/应该基于一个方法来实现

static void addToEachElement1D(int array[], int valueToAdd) { ... }

which simplifies the implementation of the 2D variant, and may also serve as a useful building block for other tasks. 这简化了2D变体的实现,并且还可以用作其他任务的有用构建块。


However, here is one possible solution for the given task: 但是,这是给定任务的一种可能解决方案:

import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class MultiDarrays
{
    public static void main(String[] args)
    {
        int array[][] = new int[][]
        {
            { 1, 2 },
            { 1 },
            { 3, 4 },
            { 2, 3, 4 } 
        };

        int result[][] = unjag(array);    
        System.out.println(Arrays.deepToString(result));
    }

    private static int[][] unjag(int array[][])
    {
        int width = computeMaxValue(array);
        return unjag(array, width);
    }

    private static int[][] unjag(int array[][], int width)
    {
        int result[][] = new int[array.length][width];
        for (int i = 0; i < result.length; i++)
        {
            result[i] = unjag(array[i], width);
        }
        return result;
    }

    private static int[] unjag(int array[], int width)
    {
        int result[] = new int[width];
        for (int i = 0; i < array.length; i++)
        {
            int value = array[i];
            result[value - 1] = value;
        }
        return result;
    }

    private static int computeMaxValue(int array[][])
    {
        return Stream.of(array)
            .flatMapToInt(a -> IntStream.of(a))
            .max().getAsInt();
    }
}

It computes the maximum value of any of the inner arrays, which is also the width of the resulting 2D array. 它计算任何内部数组的最大值,这也是所得2D数组的宽度。 Then it "unjags" the 2D array by "unjagging" each row of the input array to have the desired width. 然后,通过“取消对齐”输入数组的每一行以使其具有所需的宽度,从而“取消对齐” 2D数组。

I think you can't avoid two loops, but that is all: 我认为您无法避免两个循环,仅此而已:

  1. Calculate the width for the proper array via checking the first element of each sub-array 通过检查每个子数组的第一个元素来计算适当数组的宽度
  2. Make the copies into the proper array. 将副本放入适当的阵列中。

Lists are not involved. 列表不涉及。
Code with your example numbers: 用示例编号进行编码:

public static void main(String[] args) {
  int data[][]={{1, 2}, {1}, {3, 4}, {2, 3, 4}};
  int maxwidth=0;
  for(int line[]: data){
    maxwidth=Math.max(maxwidth, line[0]-1+line.length);
  }
  System.out.println(maxwidth);
  int proper[][]=new int[data.length][maxwidth];
  for(int i=0;i<data.length;i++){
    int line[]=data[i];
    System.arraycopy(line, 0, proper[i], line[0]-1, line.length);
  }

  for(int line[]: proper){
    for(int i=0;i<line.length-1;i++)
      System.out.print(line[i]+",");
    System.out.println(line[line.length-1]);
  }
}


If @Tom is right about putting individual elements into individual locations (not just to a continuous "slot" indexed by the first element): 如果@Tom正确地将各个元素放置在各个位置(而不仅仅是放置在第一个元素所索引的连续“槽”中):

 public static void main(String[] args) { int data[][]={{1, 2}, {1}, {3, 4}, {2, 3, 4}, {1, 5}}; int max=0; for(int line[]: data) for(int val: line) max=Math.max(max,val); System.out.println(max); int proper[][]=new int[data.length][max]; for(int i=0;i<data.length;i++){ int line[]=data[i]; for(int val: line) proper[i][val-1]=val; } for(int line[]: proper){ for(int i=0;i<line.length-1;i++) System.out.print(line[i]+","); System.out.println(line[line.length-1]); } } 

I really can not tell which approach you meant, and the example numbers are very unhelpful here. 我真的不能说出您的意思是什么方法,示例编号在这里非常无济于事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM