将二维锯齿状数组转换为正确的数组 Java
Convert 2D jagged array to proper array Java
我正在尝试解决以下问题:我有一个二维锯齿状数组
[[1, 2], [1], [3, 4], [2, 3, 4]]
我想将其转换为普通二维数组。目前,我设法得到了这个
[[1, 2, 0, 0], [1, 0, 0, 0], [3, 4, 0, 0], [2, 3, 4, 0]]
但这不是我想要的。目标是让一个正常的数组索引等于原始的锯齿状索引。
换句话说,我想将原始交错数组中的值与新适当数组中从 1 开始的索引匹配。 这是我想要的输出
[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]]
这是我生成这个数组的代码,这不是我想要的:
[[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));
}
}
输出:
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]]
当您想将值写入它们所代表的正确索引时,您不能只执行 full_array[i][j] = array[i][j]
,因为这会忽略值而只是简单地 "fills" 数组,因为 j
正常递增。
您实际需要做的是使用 array[i][j]
的值作为索引规范:
full_array[i][array[i][j] - 1] = array[i][j];
请注意,您需要减少 1,因为您的值从“1”开始,但数组索引从“0”开始。
现在输出就像您期望的那样:
[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]]
现在进行一些小的代码改进。
ArrayList<ArrayList<Integer>> multilist = new ArrayList<ArrayList<Integer>>();
应该重构为 List<List<Integer>> multilist = new ArrayList<>();
,因为应该将您的类型声明为 open,但作为 narrow 因为他们需要。您需要一个列表,但实际上您并不关心它们是 ArrayList 还是 LinkedList。另请阅读 Java - declaring from Interface type instead of Class.
不需要此转换 multilist.add((ArrayList<Integer>) integers)
。您必须添加,因为您(正确地)将 integers
声明为 List<Integer>
而不是 ArrayList<Integer>
,但是因为我们在“1”中修复了它。你不再需要它了。
for (int i = 0; i < multilist.size(); i++) {
System.out.println("Elements are: " + multilist.get(i));
}
可以替换为 enhanced-for-loop:
for (List<Integer> integers : multilist) {
System.out.println("Elements are: " + integers);
}
当前形式的代码存在几个一般性问题。
测试它很烦人,因为您总是必须输入输入值。一次定义它们,以便您可以快速轻松地测试您的代码。
List
的使用并不是真正必要的。当您的输入和输出确实是 int[]
数组时,您可以根据这些实现转换。虽然在很多情况下,List
有优势,但怀疑你可以在int[]
和List<Integer>
之间以及int[][]
和List<List<Integer>>
之间添加转换方法。
一般来说,当你有一个像int[][]
或List<List<Integer>>
这样的多维数据结构的任务,并且你想对内部元素执行操作时,创建一个专门的方法。作为一个简化的例子:当你有一个像
这样的方法时
static void addToEachElement2D(int array[][], int valueToAdd) { ... }
那么这个方法could/should是基于一个方法
实现的
static void addToEachElement1D(int array[], int valueToAdd) { ... }
简化了 2D
变体的实现,也可以作为其他任务的有用构建块。
但是,对于给定的任务,这是一种可能的解决方案:
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();
}
}
它计算任何内部数组的最大值,这也是生成的二维数组的宽度。然后它 "unjags" 二维数组 "unjagging" 输入数组的每一行都具有所需的宽度。
我认为你无法避免两个循环,但仅此而已:
- 通过检查每个 sub-array
的第一个元素来计算正确数组的宽度
- 将副本放入适当的数组中。
不涉及列表。
使用您的示例编号编写代码:
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]);
}
}
如果@Tom 将各个元素放入各个位置是正确的(不仅仅是由第一个元素索引的连续 "slot"):
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]);
}
}
我真的不知道你指的是哪种方法,这里的示例数字也没什么用。
我正在尝试解决以下问题:我有一个二维锯齿状数组
[[1, 2], [1], [3, 4], [2, 3, 4]]
我想将其转换为普通二维数组。目前,我设法得到了这个
[[1, 2, 0, 0], [1, 0, 0, 0], [3, 4, 0, 0], [2, 3, 4, 0]]
但这不是我想要的。目标是让一个正常的数组索引等于原始的锯齿状索引。 换句话说,我想将原始交错数组中的值与新适当数组中从 1 开始的索引匹配。 这是我想要的输出
[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]]
这是我生成这个数组的代码,这不是我想要的:
[[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));
}
}
输出:
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]]
当您想将值写入它们所代表的正确索引时,您不能只执行 full_array[i][j] = array[i][j]
,因为这会忽略值而只是简单地 "fills" 数组,因为 j
正常递增。
您实际需要做的是使用 array[i][j]
的值作为索引规范:
full_array[i][array[i][j] - 1] = array[i][j];
请注意,您需要减少 1,因为您的值从“1”开始,但数组索引从“0”开始。
现在输出就像您期望的那样:
[[1, 2, 0, 0], [1, 0, 0, 0], [0, 0, 3, 4], [0, 2, 3, 4]]
现在进行一些小的代码改进。
ArrayList<ArrayList<Integer>> multilist = new ArrayList<ArrayList<Integer>>();
应该重构为List<List<Integer>> multilist = new ArrayList<>();
,因为应该将您的类型声明为 open,但作为 narrow 因为他们需要。您需要一个列表,但实际上您并不关心它们是 ArrayList 还是 LinkedList。另请阅读 Java - declaring from Interface type instead of Class.不需要此转换
multilist.add((ArrayList<Integer>) integers)
。您必须添加,因为您(正确地)将integers
声明为List<Integer>
而不是ArrayList<Integer>
,但是因为我们在“1”中修复了它。你不再需要它了。for (int i = 0; i < multilist.size(); i++) { System.out.println("Elements are: " + multilist.get(i)); }
可以替换为 enhanced-for-loop:
for (List<Integer> integers : multilist) { System.out.println("Elements are: " + integers); }
当前形式的代码存在几个一般性问题。
测试它很烦人,因为您总是必须输入输入值。一次定义它们,以便您可以快速轻松地测试您的代码。
List
的使用并不是真正必要的。当您的输入和输出确实是 int[]
数组时,您可以根据这些实现转换。虽然在很多情况下,List
有优势,但怀疑你可以在int[]
和List<Integer>
之间以及int[][]
和List<List<Integer>>
之间添加转换方法。
一般来说,当你有一个像int[][]
或List<List<Integer>>
这样的多维数据结构的任务,并且你想对内部元素执行操作时,创建一个专门的方法。作为一个简化的例子:当你有一个像
static void addToEachElement2D(int array[][], int valueToAdd) { ... }
那么这个方法could/should是基于一个方法
实现的static void addToEachElement1D(int array[], int valueToAdd) { ... }
简化了 2D
变体的实现,也可以作为其他任务的有用构建块。
但是,对于给定的任务,这是一种可能的解决方案:
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();
}
}
它计算任何内部数组的最大值,这也是生成的二维数组的宽度。然后它 "unjags" 二维数组 "unjagging" 输入数组的每一行都具有所需的宽度。
我认为你无法避免两个循环,但仅此而已:
- 通过检查每个 sub-array 的第一个元素来计算正确数组的宽度
- 将副本放入适当的数组中。
不涉及列表。
使用您的示例编号编写代码:
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]);
}
}
如果@Tom 将各个元素放入各个位置是正确的(不仅仅是由第一个元素索引的连续 "slot"):
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]);
}
}
我真的不知道你指的是哪种方法,这里的示例数字也没什么用。